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'))
31 ################################################
38 <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
39 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
40 <eLabel position="78,54" size="180,144" />
41 <eLabel position="274,54" size="180,144" />
42 <eLabel position="470,54" size="180,144" />
43 <eLabel position="78,221" size="180,144" />
44 <eLabel position="274,221" size="180,144" />
45 <eLabel position="470,221" size="180,144" />
46 <eLabel position="78,388" size="180,144" />
47 <eLabel position="274,388" size="180,144" />
48 <eLabel position="470,388" size="180,144" />
49 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
50 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
51 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
52 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
53 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
54 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
55 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
56 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
57 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
58 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
59 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
60 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
61 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
62 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
63 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
64 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
65 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
66 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
67 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
68 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
69 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
70 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
71 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
72 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
73 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
74 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
75 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
76 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
77 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
78 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
79 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
80 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
81 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
82 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
83 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
84 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
85 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
86 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
89 def __init__(self, session, services):
90 Screen.__init__(self, session)
92 self.session = session
93 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
94 self.container = eConsoleAppContainer()
95 self.aspect = AVSwitch().getAspectRatioSetting()
96 self.serviceHandler = eServiceCenter.getInstance()
97 self.ref_list = services
98 self.window_refs = [None, None, None, None, None, None, None, None, None]
99 self.current_refidx = 0
100 self.current_window = 1
101 self.countdown = config.plugins.Mosaic.countdown.value
103 self.state = self.PLAY
105 self["playState"] = Pixmap()
106 for i in range(1, 10):
107 self["window" + str(i)] = Pixmap()
108 self["video" + str(i)] = VideoWindow(decoder = 0)
109 self["video" + str(i)].hide()
110 self["channel" + str(i)] = Label("")
111 self["event" + str(i)] = Label("")
112 self["event" + str(i)].hide()
113 self["video1"].decoder = 0
114 self["video1"].show()
115 self["countdown"] = Label()
116 self.updateCountdownLabel()
117 self["count"] = Label()
119 self["actions"] = NumberActionMap(["MosaicActions"],
122 "cancel": self.closeWithOldService,
124 "yellow": self.pause,
125 "channelup": self.countdownPlus,
126 "channeldown": self.countdownMinus,
127 "1": self.numberPressed,
128 "2": self.numberPressed,
129 "3": self.numberPressed,
130 "4": self.numberPressed,
131 "5": self.numberPressed,
132 "6": self.numberPressed,
133 "7": self.numberPressed,
134 "8": self.numberPressed,
135 "9": self.numberPressed
138 self.updateTimer = eTimer()
139 self.updateTimer.timeout.get().append(self.updateCountdown)
140 self.checkTimer = eTimer()
141 self.checkTimer.timeout.get().append(self.checkGrab)
143 self.container.appClosed.append(self.showNextScreenshot)
144 self.checkTimer.start(500, 1)
147 if fileExists(grab_binary):
148 # Start the first service in the bouquet and show the service-name
149 ref = self.ref_list[0]
150 self.window_refs[0] = ref
151 info = self.serviceHandler.info(ref)
152 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
153 event_name = self.getEventName(info, ref)
154 self["channel1"].setText(name)
155 self["event1"].setText(event_name)
156 self.session.nav.playService(ref)
157 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
158 self["playState"].instance.setPixmap(playingIcon)
160 # Start updating the video-screenshots
161 self.updateTimer.start(1, 1)
163 self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
165 def exit(self, callback=None):
168 def closeWithOldService(self):
169 self.session.nav.playService(self.oldService)
172 def numberPressed(self, number):
173 ref = self.window_refs[number-1]
175 self.session.nav.playService(ref)
179 if self.working == False and self.state == self.PAUSE:
180 self.state = self.PLAY
181 self.updateTimer.start(1000, 1)
182 self["playState"].instance.setPixmap(playingIcon)
185 if self.working == False and self.state == self.PLAY:
186 self.state = self.PAUSE
187 self.updateTimer.stop()
188 self["playState"].instance.setPixmap(pausedIcon)
190 def countdownPlus(self):
191 self.changeCountdown(1)
193 def countdownMinus(self):
194 self.changeCountdown(-1)
196 def changeCountdown(self, direction):
197 if self.working == False:
198 configNow = config.plugins.Mosaic.countdown.value
199 configNow += direction
201 if configNow < config_limits[0]:
202 configNow = config_limits[0]
203 elif configNow > config_limits[1]:
204 configNow = config_limits[1]
206 config.plugins.Mosaic.countdown.value = configNow
207 config.plugins.Mosaic.countdown.save()
209 self.updateCountdownLabel()
211 def makeNextScreenshot(self):
213 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
214 self.showNextScreenshot(-1)
216 def showNextScreenshot(self, callback):
217 # Resize screenshot and show in the current window
218 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
219 self["window" + str(self.current_window)].instance.setPixmap(picture)
221 # Hide current video-window and show the running event-name
222 self["video" + str(self.current_window)].hide()
223 self["event" + str(self.current_window)].show()
226 self.current_refidx += 1
227 if self.current_refidx > (len(self.ref_list) -1):
228 self.current_refidx = 0
231 ref = self.ref_list[self.current_refidx]
232 info = self.serviceHandler.info(ref)
233 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
234 event_name = self.getEventName(info, ref)
235 self.session.nav.playService(ref)
237 # Get next window index
238 self.current_window += 1
239 if self.current_window > 9:
240 self.current_window = 1
243 self.window_refs[self.current_window-1] = ref
245 # Save the event-name and hide the label
246 self["event" + str(self.current_window)].hide()
247 self["event" + str(self.current_window)].setText(event_name)
249 # Show the new video-window
250 self["video" + str(self.current_window)].show()
251 self["video" + str(self.current_window)].decoder = 0
253 # Show the servicename
254 self["channel" + str(self.current_window)].setText(name)
255 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
259 self.updateTimer.start(1, 1)
261 def updateCountdown(self, callback=None):
263 self.updateCountdownLabel()
264 if self.countdown == 0:
265 self.countdown = config.plugins.Mosaic.countdown.value
267 self.makeNextScreenshot()
269 self.updateTimer.start(1000, 1)
271 def updateCountdownLabel(self):
272 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
274 def getEventName(self, info, ref):
275 event = info.getEvent(ref)
276 if event is not None:
277 eventName = event.getEventName()
278 if eventName is None:
284 ################################################
285 # Most stuff stolen from the GraphMultiEPG
289 BouquetSelectorScreen = None
291 def getBouquetServices(bouquet):
293 Servicelist = eServiceCenter.getInstance().list(bouquet)
294 if Servicelist is not None:
296 service = Servicelist.getNext()
297 if not service.valid():
299 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
301 services.append(service)
304 def closeBouquetSelectorScreen(ret=None):
305 if BouquetSelectorScreen is not None:
306 BouquetSelectorScreen.close()
308 def openMosaic(bouquet):
309 if bouquet is not None:
310 services = getBouquetServices(bouquet)
312 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
314 def main(session, servicelist, **kwargs):
318 Servicelist = servicelist
319 global BouquetSelectorScreen
321 bouquets = Servicelist.getBouquetList()
322 if bouquets is not None:
323 if len(bouquets) == 1:
324 self.openMosaic(bouquets[0][1])
325 elif len(bouquets) > 1:
326 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
328 def Plugins(**kwargs):
329 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)