6 # Coded by Dr.Best (c) 2010
7 # Coding idea and design by Vali
8 # Support: www.dreambox-tools.info
10 # This plugin is licensed under the Creative Commons
11 # Attribution-NonCommercial-ShareAlike 3.0 Unported
12 # License. To view a copy of this license, visit
13 # http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
14 # Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
16 # Alternatively, this plugin may be distributed and executed on hardware which
17 # is licensed by Dream Multimedia GmbH.
19 # This plugin is NOT free software. It is open source, you are allowed to
20 # modify it (if you keep the license), but it may not be commercially
21 # distributed other than under the conditions noted above.
24 from Plugins.Plugin import PluginDescriptor
\r
25 from Screens.Screen import Screen
\r
26 from Components.ActionMap import ActionMap, NumberActionMap
\r
27 from Components.Label import Label
\r
28 from enigma import eServiceReference, eTimer, getDesktop
\r
29 from ServiceReference import ServiceReference
\r
30 from Components.SystemInfo import SystemInfo
31 from enigma import eServiceCenter, getBestPlayableServiceReference
32 from Components.VideoWindow import VideoWindow
33 from enigma import ePoint, eEPGCache
34 from time import localtime, time
35 from Screens.InfoBarGenerics import InfoBarShowHide, NumberZap
36 from Screens.InfoBar import InfoBar
38 from Components.Sources.StaticText import StaticText
39 from Screens.MessageBox import MessageBox
40 from Screens.Standby import TryQuitMainloop
42 from Screens.EpgSelection import EPGSelection
43 from Screens.EventView import EventViewEPGSelect
45 InfoBarShowHideINIT = None
47 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigYesNo, getConfigListEntry, configfile
48 from Components.ConfigList import ConfigList, ConfigListScreen
50 # for localized messages
53 config.plugins.virtualzap = ConfigSubsection()
54 config.plugins.virtualzap.mode = ConfigSelection(default="0", choices = [("0", _("as plugin in extended bar")),("1", _("with long OK press")), ("2", _("with exit button"))])
55 config.plugins.virtualzap.usepip = ConfigYesNo(default = True)
57 def autostart(reason, **kwargs):
58 if config.plugins.virtualzap.mode.value != "0":
59 # overide InfoBarShowHide
60 global InfoBarShowHideINIT
61 if InfoBarShowHideINIT is None:
62 InfoBarShowHideINIT = InfoBarShowHide.__init__
63 InfoBarShowHide.__init__ = InfoBarShowHide__init__
65 InfoBarShowHide.showVZ = showVZ
66 if config.plugins.virtualzap.mode.value == "2":
67 InfoBarShowHide.newHide = newHide
69 def InfoBarShowHide__init__(self):
70 # initialize InfoBarShowHide with original __init__
71 InfoBarShowHideINIT(self)
72 # delete current key map --> we have to use "ok" with b-flag
73 if config.plugins.virtualzap.mode.value == "1":
74 del self["ShowHideActions"]
75 # initialize own actionmap with ok = b and longOK = l
76 self["myactions"] = ActionMap( ["myShowHideActions"] ,
78 "toggleShow": self.toggleShow,
79 "longOK": self.showVZ,
82 elif config.plugins.virtualzap.mode.value == "2":
83 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
85 "toggleShow": self.toggleShow,
91 from Screens.InfoBarGenerics import InfoBarEPG, InfoBarPiP
92 # check for InfoBarEPG --> only start if true
93 if isinstance(self, InfoBarEPG):
95 if isinstance(self, InfoBarPiP):
96 # check if PiP is already shown
100 if isinstance(self, InfoBar):
101 self.session.open(VirtualZap, self.servicelist)
104 # remember if infobar is shown
108 # infobar was not shown, start VZ
111 def Plugins(**kwargs):
112 plist = [PluginDescriptor(name="Virtual Zap Setup", description=_("Virtual Zap Setup"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "plugin.png", fnc = setup)]
113 if config.plugins.virtualzap.mode.value == "0":
114 plist.append(PluginDescriptor(name="Virtual Zap", description=_("Virtual (PiP) Zap"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU],icon = "plugin.png", fnc = main))
115 elif config.plugins.virtualzap.mode.value == "1" or config.plugins.virtualzap.mode.value == "2":
116 plist.append(PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART],fnc = autostart))
119 def setup(session,**kwargs):
120 session.open(VirtualZapConfig)
122 def main(session,**kwargs):
123 session.open(VirtualZap, kwargs["servicelist"])
125 class VirtualZap(Screen):
\r
126 sz_w = getDesktop(0).size().width()
129 # VirtualZap or VirtualZapNoPiP
132 if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value:
135 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,505" size="1280,220" title="Virtual Zap">
136 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/hd.png" position="0,0" size="1280,220" zPosition="0"/>
137 <widget backgroundColor="transparent" name="video" position="60,50" size="214,120" zPosition="1"/>
138 <widget backgroundColor="#101214" font="Regular;26" halign="left" name="NowChannel" position="305,60" size="887,32" transparent="1" zPosition="2"/>
139 <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="left" name="NowEPG" position="305,105" size="600,28" transparent="1" zPosition="2"/>
140 <widget backgroundColor="#101214" font="Regular;24" halign="left" name="NextEPG" position="305,140" size="600,28" transparent="1" zPosition="2"/>
141 <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="right" name="NowTime" position="1070,105" size="124,28" transparent="1" zPosition="2"/>
142 <widget backgroundColor="#101214" font="Regular;24" halign="right" name="NextTime" position="1070,140" size="124,28" transparent="1" zPosition="2"/>
146 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,420" size="1024,176" title="Virtual Zap">
147 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="1024,176" zPosition="0"/>
148 <widget backgroundColor="transparent" name="video" position="50,20" size="164,92" zPosition="1"/>
149 <widget backgroundColor="#101214" font="Regular;22" halign="left" name="NowChannel" position="230,25" size="741,30" transparent="1" zPosition="2"/>
150 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="230,55" size="600,25" transparent="1" zPosition="2"/>
151 <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="230,80" size="600,25" transparent="1" zPosition="2"/>
152 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="850,55" size="124,25" transparent="1" zPosition="2"/>
153 <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="850,80" size="124,25" transparent="1" zPosition="2"/>
157 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,420" size="720,176" title="Virtual Zap">
158 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="720,176" zPosition="0"/>
159 <widget backgroundColor="transparent" name="video" position="50,25" size="130,73" zPosition="1"/>
160 <widget backgroundColor="#101214" font="Regular;22" halign="left" name="NowChannel" position="190,25" size="480,30" transparent="1" zPosition="2"/>
161 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="190,55" size="360,25" transparent="1" zPosition="2"/>
162 <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="190,80" size="360,25" transparent="1" zPosition="2"/>
163 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="550,55" size="120,25" transparent="1" zPosition="2"/>
164 <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="550,80" size="120,25" transparent="1" zPosition="2"/>
169 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,505" size="1280,220" title="Virtual Zap">
170 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/hd.png" position="0,0" size="1280,220" zPosition="0"/>
171 <widget backgroundColor="#101214" font="Regular;26" halign="center" name="NowChannel" position="140,60" size="1000,32" transparent="1" zPosition="2"/>
172 <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="left" name="NowEPG" position="140,105" size="860,28" transparent="1" zPosition="2"/>
173 <widget backgroundColor="#101214" font="Regular;24" halign="left" name="NextEPG" position="140,140" size="860,28" transparent="1" zPosition="2"/>
174 <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="right" name="NowTime" position="1015,105" size="124,28" transparent="1" zPosition="2"/>
175 <widget backgroundColor="#101214" font="Regular;24" halign="right" name="NextTime" position="1015,140" size="124,28" transparent="1" zPosition="2"/>
179 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,420" size="1024,176" title="Virtual Zap">
180 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="1024,176" zPosition="0"/>
181 <widget backgroundColor="#101214" font="Regular;22" halign="center" name="NowChannel" position="100,25" size="824,30" transparent="1" zPosition="2"/>
182 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="100,55" size="700,25" transparent="1" zPosition="2"/>
183 <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="100,80" size="700,25" transparent="1" zPosition="2"/>
184 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="800,55" size="124,25" transparent="1" zPosition="2"/>
185 <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="800,80" size="124,25" transparent="1" zPosition="2"/>
189 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,420" size="720,176" title="Virtual Zap">
190 <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="720,176" zPosition="0"/>
191 <widget backgroundColor="#101214" font="Regular;22" halign="center" name="NowChannel" position="50,25" size="620,30" transparent="1" zPosition="2"/>
192 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="50,55" size="500,25" transparent="1" zPosition="2"/>
193 <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="50,80" size="500,25" transparent="1" zPosition="2"/>
194 <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="550,55" size="120,25" transparent="1" zPosition="2"/>
195 <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="550,80" size="120,25" transparent="1" zPosition="2"/>
199 def __init__(self, session, servicelist = None):
\r
200 Screen.__init__(self, session)
\r
201 self.session = session
202 self.pipAvailable = False
203 if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value:
204 self.skinName = "VirtualZap"
205 self.pipAvailable = True
207 self.skinName = "VirtualZapNoPiP"
208 self.epgcache = eEPGCache.getInstance()
\r
209 self.CheckForEPG = eTimer()
\r
210 self.CheckForEPG.callback.append(self.CheckItNow)
\r
211 self["NowChannel"] = Label()
\r
212 self["NowEPG"] = Label()
\r
213 self["NextEPG"] = Label()
214 self["NowTime"] = Label()
\r
215 self["NextTime"] = Label()
\r
216 self["actions"] = ActionMap(["OkCancelActions", "DirectionActions", "ChannelSelectBaseActions", "ChannelSelectEPGActions"],
219 "cancel": self.closing,
\r
220 "right": self.nextService,
\r
221 "left": self.prevService,
222 "nextBouquet": self.nextBouquet,
223 "prevBouquet": self.prevBouquet,
224 "showEPGList": self.openEventView,
226 self["actions2"] = NumberActionMap(["NumberActions"],
228 "1": self.keyNumberGlobal,
229 "2": self.keyNumberGlobal,
230 "3": self.keyNumberGlobal,
231 "4": self.keyNumberGlobal,
232 "5": self.keyNumberGlobal,
233 "6": self.keyNumberGlobal,
234 "7": self.keyNumberGlobal,
235 "8": self.keyNumberGlobal,
236 "9": self.keyNumberGlobal,
238 self.onLayoutFinish.append(self.onLayoutReady)
240 if self.pipAvailable:
241 # activate PiP support
242 self["video"] = VideoWindow(fb_width = getDesktop(0).size().width(), fb_height = getDesktop(0).size().height())
245 # this is the servicelist from ChannelSelectionBase
246 self.servicelist = servicelist
247 self.newServicePlayed = False
248 # needed, because if we won't zap, we habe to go back to the current bouquet and service
249 self.curRef = ServiceReference(self.servicelist.getCurrentSelection())
250 self.curBouquet = self.servicelist.getRoot()
252 def onLayoutReady(self):
255 def nextService(self):
257 if self.servicelist.inBouquet():
258 prev = self.servicelist.getCurrentSelection()
260 prev = prev.toString()
262 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
263 self.servicelist.nextBouquet()
265 self.servicelist.moveDown()
266 cur = self.servicelist.getCurrentSelection()
267 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
270 self.servicelist.moveDown()
271 if self.isPlayable():
276 def prevService(self):
277 # get previous service
278 if self.servicelist.inBouquet():
279 prev = self.servicelist.getCurrentSelection()
281 prev = prev.toString()
283 if config.usage.quickzap_bouquet_change.value:
284 if self.servicelist.atBegin():
285 self.servicelist.prevBouquet()
286 self.servicelist.moveUp()
287 cur = self.servicelist.getCurrentSelection()
288 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
291 self.servicelist.moveUp()
292 if self.isPlayable():
297 def isPlayable(self):
298 # check if service is playable
299 current = ServiceReference(self.servicelist.getCurrentSelection())
300 return not (current.ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
303 def nextBouquet(self):
304 # next bouquet with first service
305 if config.usage.multibouquet.value:
306 self.servicelist.nextBouquet()
309 def prevBouquet(self):
310 # previous bouquet with first service
311 if config.usage.multibouquet.value:
312 self.servicelist.prevBouquet()
316 def updateInfos(self):
318 current = ServiceReference(self.servicelist.getCurrentSelection())
319 self["NowChannel"].setText(current.getServiceName())
320 nowepg, nowtimedisplay = self.getEPGNowNext(current.ref,0)
321 nextepg, nexttimedisplay = self.getEPGNowNext(current.ref,1)
322 self["NowEPG"].setText(nowepg)
323 self["NextEPG"].setText(nextepg)
324 self["NowTime"].setText(nowtimedisplay)
325 self["NextTime"].setText(nexttimedisplay)
327 # no epg found --> let's try it again, but only if PiP is activated
328 if self.pipAvailable:
329 self.CheckForEPG.start(3000, True)
330 if self.pipAvailable:
331 # play in videowindow
332 self.playService(current.ref)
334 def getEPGNowNext(self,ref, modus):
335 # get now || next event
336 if self.epgcache is not None:
337 event = self.epgcache.lookupEvent(['IBDCTSERNX', (ref.toString(), modus, -1)])
340 t = localtime(event[0][1])
341 duration = event[0][2]
343 timedisplay = "+%d min" % (((event[0][1] + duration) - time()) / 60)
345 timedisplay = "%d min" % (duration / 60)
346 return "%02d:%02d %s" % (t[3],t[4], event[0][4]), timedisplay
351 def openSingleServiceEPG(self):
353 current = ServiceReference(self.servicelist.getCurrentSelection())
354 self.session.open(EPGSelection, current.ref)
356 def openEventView(self):
359 self.epglist = epglist
360 service = ServiceReference(self.servicelist.getCurrentSelection())
362 evt = self.epgcache.lookupEventTime(ref, -1)
365 evt = self.epgcache.lookupEventTime(ref, -1, 1)
369 self.session.open(EventViewEPGSelect, epglist[0], service, self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
371 def eventViewCallback(self, setEvent, setService, val):
372 epglist = self.epglist
375 epglist[0] = epglist[1]
379 def openMultiServiceEPG(self):
383 def openSimilarList(self, eventid, refstr):
384 self.session.open(EPGSelection, refstr, None, eventid)
387 if self.pipAvailable:
388 self.pipservice = None
389 if not self.newServicePlayed:
390 # we need to select the old service with bouquet
391 if self.curBouquet != self.servicelist.getRoot():
392 self.servicelist.clearPath()
393 if self.servicelist.bouquet_root != self.curBouquet:
394 self.servicelist.enterPath(self.servicelist.bouquet_root)
395 self.servicelist.enterPath(self.curBouquet)
396 self.servicelist.setCurrentSelection(self.curRef.ref)
400 # we have to close PiP first, otherwise the service-display is freezed
401 if self.pipAvailable:
402 self.pipservice = None
403 # play selected service and close virtualzap
404 self.newServicePlayed = True
\r
405 self.servicelist.zap()
\r
408 def CheckItNow(self):
\r
409 self.CheckForEPG.stop()
\r
412 # if available play service in PiP
413 def playService(self, service):
414 if service and (service.flags & eServiceReference.isGroup):
415 ref = getBestPlayableServiceReference(service, eServiceReference())
418 if ref and ref.toString() != self.currentPiP:
419 self.pipservice = eServiceCenter.getInstance().play(ref)
420 if self.pipservice and not self.pipservice.setTarget(1):
421 self.pipservice.start()
422 self.currentPiP = ref.toString()
424 self.pipservice = None
428 # switch with numbers
429 def keyNumberGlobal(self, number):
430 self.session.openWithCallback(self.numberEntered, NumberZap, number)
432 def numberEntered(self, retval):
434 self.zapToNumber(retval)
436 def searchNumberHelper(self, serviceHandler, num, bouquet):
437 servicelist = serviceHandler.list(bouquet)
438 if not servicelist is None:
440 serviceIterator = servicelist.getNext()
441 if not serviceIterator.valid(): #check end of list
443 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
446 if not num: #found service with searched number ?
447 return serviceIterator, 0
450 def zapToNumber(self, number):
451 bouquet = self.servicelist.bouquet_root
453 serviceHandler = eServiceCenter.getInstance()
454 bouquetlist = serviceHandler.list(bouquet)
455 if not bouquetlist is None:
457 bouquet = bouquetlist.getNext()
458 if not bouquet.valid(): #check end of list
460 if bouquet.flags & eServiceReference.isDirectory:
461 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
462 if not service is None:
463 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
464 self.servicelist.clearPath()
465 if self.servicelist.bouquet_root != bouquet:
466 self.servicelist.enterPath(self.servicelist.bouquet_root)
467 self.servicelist.enterPath(bouquet)
468 self.servicelist.setCurrentSelection(service) #select the service in servicelist
469 # update infos, no matter if service is none or not
474 class VirtualZapConfig(Screen, ConfigListScreen):
477 <screen position="center,center" size="560,110" title="Virtual Zap Config" >
478 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
479 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
480 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
481 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
482 <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
483 <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
484 <widget name="config" position="20,50" size="520,330" scrollbarMode="showOnDemand" />
487 def __init__(self, session):
488 Screen.__init__(self, session)
489 self["key_red"] = StaticText(_("Cancel"))
490 self["key_green"] = StaticText(_("OK"))
492 self.list.append(getConfigListEntry(_("Usage"), config.plugins.virtualzap.mode))
493 if SystemInfo.get("NumVideoDecoders", 1) > 1:
494 self.list.append(getConfigListEntry(_("Show with PiP"), config.plugins.virtualzap.usepip))
495 ConfigListScreen.__init__(self, self.list, session)
496 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
498 "green": self.keySave,
499 "cancel": self.keyClose,
503 for x in self["config"].list:
506 restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("GUI needs a restart to apply the new settings.\nDo you want to Restart the GUI now?"), MessageBox.TYPE_YESNO)
507 restartbox.setTitle(_("Restart GUI now?"))
511 for x in self["config"].list:
515 def restartGUI(self, answer):
517 self.session.open(TryQuitMainloop, 3)