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.Pixmap import Pixmap
11 from Components.VideoWindow import VideoWindow
12 from enigma import eConsoleAppContainer, eServiceCenter, eServiceReference, eTimer, loadPic, loadPNG
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
19 ################################################
21 grab_binary = "/usr/bin/grab"
22 grab_picture = "/tmp/.mosaic.bmp"
24 config_limits = (3, 30)
25 config.plugins.Mosaic = ConfigSubsection()
26 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
28 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
29 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
36 ################################################
43 <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
44 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
45 <eLabel position="78,54" size="180,144" />
46 <eLabel position="274,54" size="180,144" />
47 <eLabel position="470,54" size="180,144" />
48 <eLabel position="78,221" size="180,144" />
49 <eLabel position="274,221" size="180,144" />
50 <eLabel position="470,221" size="180,144" />
51 <eLabel position="78,388" size="180,144" />
52 <eLabel position="274,388" size="180,144" />
53 <eLabel position="470,388" size="180,144" />
54 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
55 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
56 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
57 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
58 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
59 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
60 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
61 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
62 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
63 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
64 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
65 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
66 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
67 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
68 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
69 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
70 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
71 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
72 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
73 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
74 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
75 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
76 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
77 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
78 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
79 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
80 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
81 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
82 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
83 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
84 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
85 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
86 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
87 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
88 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
89 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
90 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
91 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
94 def __init__(self, session, services):
95 Screen.__init__(self, session)
97 self.session = session
98 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
99 self.container = eConsoleAppContainer()
100 self.aspect = AVSwitch().getAspectRatioSetting()
101 self.serviceHandler = eServiceCenter.getInstance()
102 self.ref_list = services
103 self.window_refs = [None, None, None, None, None, None, None, None, None]
104 self.current_refidx = 0
105 self.current_window = 1
106 self.countdown = config.plugins.Mosaic.countdown.value
108 self.state = self.PLAY
110 self["playState"] = Pixmap()
111 for i in range(1, 10):
112 self["window" + str(i)] = Pixmap()
113 self["video" + str(i)] = VideoWindow(decoder = 0)
114 self["video" + str(i)].hide()
115 self["channel" + str(i)] = Label("")
116 self["event" + str(i)] = Label("")
117 self["event" + str(i)].hide()
118 self["video1"].decoder = 0
119 self["video1"].show()
120 self["countdown"] = Label()
121 self.updateCountdownLabel()
122 self["count"] = Label()
124 self["actions"] = NumberActionMap(["MosaicActions"],
127 "cancel": self.closeWithOldService,
129 "yellow": self.pause,
130 "channelup": self.countdownPlus,
131 "channeldown": self.countdownMinus,
132 "1": self.numberPressed,
133 "2": self.numberPressed,
134 "3": self.numberPressed,
135 "4": self.numberPressed,
136 "5": self.numberPressed,
137 "6": self.numberPressed,
138 "7": self.numberPressed,
139 "8": self.numberPressed,
140 "9": self.numberPressed
143 self.updateTimer = eTimer()
144 self.updateTimer.timeout.get().append(self.updateCountdown)
145 self.checkTimer = eTimer()
146 self.checkTimer.timeout.get().append(self.checkGrab)
148 self.container.appClosed.append(self.showNextScreenshot)
149 self.checkTimer.start(500, 1)
152 if fileExists(grab_binary):
153 # Start the first service in the bouquet and show the service-name
154 ref = self.ref_list[0]
155 self.window_refs[0] = ref
156 info = self.serviceHandler.info(ref)
157 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
158 event_name = self.getEventName(info, ref)
159 self["channel1"].setText(name)
160 self["event1"].setText(event_name)
161 self.session.nav.playService(ref)
162 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
163 self["playState"].instance.setPixmap(playingIcon)
165 # Start updating the video-screenshots
166 self.updateTimer.start(1, 1)
168 self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
170 def exit(self, callback=None):
173 def closeWithOldService(self):
174 self.session.nav.playService(self.oldService)
177 def numberPressed(self, number):
178 ref = self.window_refs[number-1]
180 self.session.nav.playService(ref)
184 if self.working == False and self.state == self.PAUSE:
185 self.state = self.PLAY
186 self.updateTimer.start(1000, 1)
187 self["playState"].instance.setPixmap(playingIcon)
190 if self.working == False and self.state == self.PLAY:
191 self.state = self.PAUSE
192 self.updateTimer.stop()
193 self["playState"].instance.setPixmap(pausedIcon)
195 def countdownPlus(self):
196 self.changeCountdown(1)
198 def countdownMinus(self):
199 self.changeCountdown(-1)
201 def changeCountdown(self, direction):
202 if self.working == False:
203 configNow = config.plugins.Mosaic.countdown.value
204 configNow += direction
206 if configNow < config_limits[0]:
207 configNow = config_limits[0]
208 elif configNow > config_limits[1]:
209 configNow = config_limits[1]
211 config.plugins.Mosaic.countdown.value = configNow
212 config.plugins.Mosaic.countdown.save()
214 self.updateCountdownLabel()
216 def makeNextScreenshot(self):
218 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
219 self.showNextScreenshot(-1)
221 def showNextScreenshot(self, callback):
222 # Resize screenshot and show in the current window
223 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
224 self["window" + str(self.current_window)].instance.setPixmap(picture)
226 # Hide current video-window and show the running event-name
227 self["video" + str(self.current_window)].hide()
228 self["event" + str(self.current_window)].show()
231 self.current_refidx += 1
232 if self.current_refidx > (len(self.ref_list) -1):
233 self.current_refidx = 0
236 ref = self.ref_list[self.current_refidx]
237 info = self.serviceHandler.info(ref)
238 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
239 event_name = self.getEventName(info, ref)
240 self.session.nav.playService(ref)
242 # Get next window index
243 self.current_window += 1
244 if self.current_window > 9:
245 self.current_window = 1
248 self.window_refs[self.current_window-1] = ref
250 # Save the event-name and hide the label
251 self["event" + str(self.current_window)].hide()
252 self["event" + str(self.current_window)].setText(event_name)
254 # Show the new video-window
255 self["video" + str(self.current_window)].show()
256 self["video" + str(self.current_window)].decoder = 0
258 # Show the servicename
259 self["channel" + str(self.current_window)].setText(name)
260 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
264 self.updateTimer.start(1, 1)
266 def updateCountdown(self, callback=None):
268 self.updateCountdownLabel()
269 if self.countdown == 0:
270 self.countdown = config.plugins.Mosaic.countdown.value
272 self.makeNextScreenshot()
274 self.updateTimer.start(1000, 1)
276 def updateCountdownLabel(self):
277 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
279 def getEventName(self, info, ref):
280 event = info.getEvent(ref)
281 if event is not None:
282 eventName = event.getEventName()
283 if eventName is None:
289 ################################################
290 # Most stuff stolen from the GraphMultiEPG
292 def getBouquetServices(bouquet):
294 Servicelist = eServiceCenter.getInstance().list(bouquet)
295 if not Servicelist is None:
297 service = Servicelist.getNext()
298 if not service.valid():
300 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
302 services.append(service)
305 def openMosaic(bouquet):
306 services = getBouquetServices(bouquet)
308 dlg_stack.append(Session.openWithCallback(closed, Mosaic, services))
318 def closed(ret=False):
319 closedScreen = dlg_stack.pop()
321 if bouquetSel and closedScreen == bouquetSel:
323 dlgs = len(dlg_stack)
325 dlg_stack[dlgs-1].close(dlgs > 1)
329 def main(session, servicelist, **kwargs):
333 Servicelist = servicelist
335 bouquets = Servicelist.getBouquetList()
343 bouquetSel = Session.openWithCallback(closed, BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
344 dlg_stack.append(bouquetSel)
346 if not openMosaic(bouquets[0][1]):
349 def Plugins(**kwargs):
350 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)