pipzap: fix typo
[enigma2-plugins.git] / pipzap / src / plugin.py
1 # Plugin definition
2 from Plugins.Plugin import PluginDescriptor
3
4 from Components.ActionMap import HelpableActionMap
5 from Components.ChoiceList import ChoiceEntryComponent
6 from Components.config import config, ConfigSubsection, ConfigEnableDisable
7 from Components.SystemInfo import SystemInfo
8 from Components.ParentalControl import parentalControl
9 from enigma import eServiceReference
10 from Screens.ChannelSelection import ChannelContextMenu, ChannelSelection, ChannelSelectionBase
11 from Screens.InfoBar import InfoBar, MoviePlayer
12 from Screens.InfoBarGenerics import InfoBarNumberZap, InfoBarEPG, InfoBarChannelSelection, InfoBarPiP, InfoBarShowMovies, InfoBarTimeshift, InfoBarSeek, InfoBarPlugins
13 from Screens.PictureInPicture import PictureInPicture
14 from Screens.Screen import Screen
15
16 #pragma mark -
17 #pragma mark ChannelSelection
18 #pragma mark -
19
20 # ChannelContextMenu: switch "Activate Picture in Picture" for pip/mainpicture
21 def ChannelContextMenu___init__(self, session, csel, *args, **kwargs):
22         ChannelContextMenu.baseInit(self, session, csel, *args, **kwargs)
23
24         list = self["menu"].list
25         x = 0
26         for entry in list:
27                 if entry[0][0] == _("Activate Picture in Picture"):
28                         if csel.dopipzap:
29                                 entry = ChoiceEntryComponent("", (_("play in mainwindow"), self.playMain))
30                         else:
31                                 entry = ChoiceEntryComponent("blue", (_("play as picture in picture"), self.showServiceInPiP))
32                         list[x] = entry
33                         break
34                 x += 1
35         self["menu"].setList(list)
36 ChannelContextMenu.baseInit = ChannelContextMenu.__init__
37 ChannelContextMenu.__init__ = ChannelContextMenu___init__
38
39 def ChannelContextMenu_playMain(self):
40         # XXX: we want to keep the current selection
41         sel = self.csel.getCurrentSelection()
42         self.csel.zap()
43         self.csel.setCurrentSelection(sel)
44         self.close()
45 ChannelContextMenu.playMain = ChannelContextMenu_playMain
46
47 # do not hide existing pip
48 def ChannelContextMenu_showServiceInPiP(self):
49         if not self.pipAvailable:
50                 return
51
52         if not self.session.pipshown:
53                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
54                 self.session.pip.show()
55
56         newservice = self.csel.servicelist.getCurrent()
57         if self.session.pip.playService(newservice):
58                 self.session.pipshown = True
59                 self.session.pip.servicePath = self.csel.getCurrentServicePath()
60                 self.close(True)
61         else:
62                 self.session.pipshown = False
63                 del self.session.pip
64                 self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
65 ChannelContextMenu.showServiceInPiP = ChannelContextMenu_showServiceInPiP
66
67 def ChannelSelectionBase__init__(self, *args, **kwargs):
68         ChannelSelectionBase.baseInit(self, *args, **kwargs)
69         self.dopipzap = False
70         self.enable_pipzap = False
71 ChannelSelectionBase.baseInit = ChannelSelectionBase.__init__
72 ChannelSelectionBase.__init__ = ChannelSelectionBase__init__
73
74 def ChannelSelectionBase_setCurrentSelection(self, service, *args, **kwargs):
75         if service:
76                 ChannelSelectionBase.baseSetCurrentSelection(self, service, *args, **kwargs)
77 ChannelSelectionBase.baseSetCurrentSelection = ChannelSelectionBase.setCurrentSelection
78 ChannelSelectionBase.setCurrentSelection = ChannelSelectionBase_setCurrentSelection
79
80 def ChannelSelection_channelSelected(self, *args, **kwargs):
81         self.enable_pipzap = True
82         ChannelSelection.baseChannelSelected(self, *args, **kwargs)
83         self.enable_pipzap = False
84 ChannelSelection.baseChannelSelected = ChannelSelection.channelSelected
85 ChannelSelection.channelSelected = ChannelSelection_channelSelected
86
87 def ChannelSelection_togglePipzap(self):
88         assert(self.session.pip)
89         title = self.instance.getTitle()
90         pos = title.find(" (")
91         if pos != -1:
92                 title = title[:pos]
93         if self.dopipzap:
94                 # Mark PiP as inactive and effectively deactivate pipzap
95                 self.session.pip.inactive()
96                 self.dopipzap = False
97
98                 # Disable PiP if not playing a service
99                 if self.session.pip.pipservice is None:
100                         self.session.pipshown = False
101                         del self.session.pip
102
103                 # Move to playing service
104                 lastservice = eServiceReference(self.lastservice.value)
105                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
106                         self.setCurrentSelection(lastservice)
107
108                 title += " (TV)"
109         else:
110                 # Mark PiP as active and effectively active pipzap
111                 self.session.pip.active()
112                 self.dopipzap = True
113
114                 # Move to service playing in pip (will not work with subservices)
115                 self.setCurrentSelection(self.session.pip.getCurrentService())
116
117                 title += " (PiP)"
118         self.setTitle(title)
119         self.buildTitleString()
120 ChannelSelection.togglePipzap = ChannelSelection_togglePipzap 
121
122 def ChannelSelection_zap(self, *args, **kwargs):
123         if self.enable_pipzap and self.dopipzap:
124                 self.revertMode=None
125                 ref = self.session.pip.getCurrentService()
126                 nref = self.getCurrentSelection()
127                 if ref is None or ref != nref:
128                         if not config.ParentalControl.configured.value or parentalControl.getProtectionLevel(nref.toCompareString()) == -1:
129                                 if not self.session.pip.playService(nref):
130                                         # XXX: Make sure we set an invalid ref
131                                         self.session.pip.playService(None)
132         else:
133                 ChannelSelection.baseZap(self, *args, **kwargs)
134
135                 # Yes, we might double-check this, but we need to re-select pipservice if pipzap is active
136                 # and we just wanted to zap in mainwindow once
137                 # XXX: do we really want this? this also resets the service when zapping from context menu
138                 #      which is irritating
139                 if self.dopipzap:
140                         # This unfortunately won't work with subservices
141                         self.setCurrentSelection(self.session.pip.getCurrentService())
142 ChannelSelection.baseZap = ChannelSelection.zap
143 ChannelSelection.zap = ChannelSelection_zap
144
145 def ChannelSelection_setHistoryPath(self, *args, **kwargs):
146         ChannelSelection.baseSetHistoryPath(self, *args, **kwargs)
147         if self.dopipzap:
148                 self.setCurrentSelection(self.session.pip.getCurrentService())
149 ChannelSelection.baseSetHistoryPath = ChannelSelection.setHistoryPath
150 ChannelSelection.setHistoryPath = ChannelSelection_setHistoryPath
151
152 def ChannelSelection_cancel(self, *args, **kwargs):
153         if self.revertMode is None and self.dopipzap:
154                 # This unfortunately won't work with subservices
155                 self.setCurrentSelection(self.session.pip.getCurrentService())
156                 self.revertMode = 1337 # not in (None, MODE_TV, MODE_RADIO)
157         ChannelSelection.baseCancel(self, *args, **kwargs)
158 ChannelSelection.baseCancel = ChannelSelection.cancel
159 ChannelSelection.cancel = ChannelSelection_cancel
160
161 #pragma mark -
162 #pragma mark MoviePlayer
163 #pragma mark -
164
165 def MoviePlayer__init__(self, *args, **kwargs):
166         MoviePlayer.baseInit(self, *args, **kwargs)
167         self.servicelist = InfoBar.instance.servicelist
168
169         # WARNING: GROSS HACK INBOUND
170         del self.list[:]
171         self.allowPiP = True
172         InfoBarPlugins.__init__(self)
173         InfoBarPiP.__init__(self)
174
175         self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
176                 {
177                         "left": self.left,
178                         "right": self.right
179                 }, prio = -2)
180 MoviePlayer.baseInit = MoviePlayer.__init__
181 MoviePlayer.__init__ = MoviePlayer__init__
182
183 def MoviePlayer_up(self):
184         slist = self.servicelist
185         if slist and slist.dopipzap:
186                 slist.moveUp()
187                 self.session.execDialog(slist)
188         else:
189                 self.showMovies()
190 MoviePlayer.up = MoviePlayer_up
191
192 def MoviePlayer_down(self):
193         slist = self.servicelist
194         if slist and slist.dopipzap:
195                 slist.moveDown()
196                 self.session.execDialog(slist)
197         else:
198                 self.showMovies()
199 MoviePlayer.down = MoviePlayer_down
200
201 def MoviePlayer_right(self):
202         # XXX: gross hack, we do not really seek if changing channel in pip :-)
203         slist = self.servicelist
204         if slist and slist.dopipzap:
205                 # XXX: We replicate InfoBarChannelSelection.zapDown here - we shouldn't do that
206                 if slist.inBouquet():
207                         prev = slist.getCurrentSelection()
208                         if prev:
209                                 prev = prev.toString()
210                                 while True:
211                                         if config.usage.quickzap_bouquet_change.value and slist.atEnd():
212                                                 slist.nextBouquet()
213                                         else:
214                                                 slist.moveDown()
215                                         cur = slist.getCurrentSelection()
216                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
217                                                 break
218                 else:
219                         slist.moveDown()
220                 slist.enable_pipzap = True
221                 slist.zap()
222                 slist.enable_pipzap = False
223         else:
224                 InfoBarSeek.seekFwd(self)
225 MoviePlayer.right = MoviePlayer_right
226
227 def MoviePlayer_left(self):
228         slist = self.servicelist
229         if slist and slist.dopipzap:
230                 # XXX: We replicate InfoBarChannelSelection.zapUp here - we shouldn't do that
231                 if slist.inBouquet():
232                         prev = slist.getCurrentSelection()
233                         if prev:
234                                 prev = prev.toString()
235                                 while True:
236                                         if config.usage.quickzap_bouquet_change.value:
237                                                 if slist.atBegin():
238                                                         slist.prevBouquet()
239                                         slist.moveUp()
240                                         cur = slist.getCurrentSelection()
241                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
242                                                 break
243                 else:
244                         slist.moveUp()
245                 slist.enable_pipzap = True
246                 slist.zap()
247                 slist.enable_pipzap = False
248         else:
249                 InfoBarSeek.seekBack(self)
250 MoviePlayer.left = MoviePlayer_left
251
252 def MoviePlayer_showPiP(self):
253         slist = self.servicelist
254         if self.session.pipshown:
255                 if slist and slist.dopipzap:
256                         slist.togglePipzap()
257                 del self.session.pip
258                 self.session.pipshown = False
259         else:
260                 from Screens.PictureInPicture import PictureInPicture
261                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
262                 self.session.pip.show()
263                 self.session.pipshown = True
264                 self.session.pip.playService(slist.getCurrentSelection())
265 MoviePlayer.showPiP = MoviePlayer_showPiP
266
267 def MoviePlayer_swapPiP(self):
268         pass
269 MoviePlayer.swapPiP = MoviePlayer_swapPiP
270
271 #pragma mark -
272 #pragma mark InfoBarGenerics
273 #pragma mark -
274
275 def InfoBarNumberZap_zapToNumber(self, *args, **kwargs):
276         self.servicelist.enable_pipzap = True
277         InfoBarNumberZap.baseZapToNumber(self, *args, **kwargs)
278         self.servicelist.enable_pipzap = False
279 InfoBarNumberZap.baseZapToNumber = InfoBarNumberZap.zapToNumber
280 InfoBarNumberZap.zapToNumber = InfoBarNumberZap_zapToNumber
281
282 def InfoBarChannelSelection_zapUp(self, *args, **kwargs):
283         self.servicelist.enable_pipzap = True
284         InfoBarChannelSelection.baseZapUp(self, *args, **kwargs)
285         self.servicelist.enable_pipzap = False
286 InfoBarChannelSelection.baseZapUp = InfoBarChannelSelection.zapUp
287 InfoBarChannelSelection.zapUp = InfoBarChannelSelection_zapUp
288
289 def InfoBarChannelSelection_zapDown(self, *args, **kwargs):
290         self.servicelist.enable_pipzap = True
291         InfoBarChannelSelection.baseZapDown(self, *args, **kwargs)
292         self.servicelist.enable_pipzap = False
293 InfoBarChannelSelection.baseZapDown = InfoBarChannelSelection.zapDown
294 InfoBarChannelSelection.zapDown = InfoBarChannelSelection_zapDown
295
296 def InfoBarEPG_zapToService(self, *args, **kwargs):
297         self.servicelist.enable_pipzap = True
298         InfoBarEPG.baseZapToService(self, *args, **kwargs)
299         self.servicelist.enable_pipzap = False
300 InfoBarEPG.baseZapToService = InfoBarEPG.zapToService
301 InfoBarEPG.zapToService = InfoBarEPG_zapToService
302
303 def InfoBarShowMovies__init__(self):
304         InfoBarShowMovies.baseInit(self)
305         self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
306                 {
307                         "movieList": (self.showMovies, _("movie list")),
308                         "up": (self.up, _("movie list")),
309                         "down": (self.down, _("movie list"))
310                 })
311 InfoBarShowMovies.baseInit = InfoBarShowMovies.__init__
312 InfoBarShowMovies.__init__ = InfoBarShowMovies__init__
313
314 def InfoBarPiP__init__(self):
315         InfoBarPiP.baseInit(self)
316         if SystemInfo.get("NumVideoDecoders", 1) > 1 and self.allowPiP:
317                 self.addExtension((self.getTogglePipzapName, self.togglePipzap, self.pipShown), "red")
318                 if config.plugins.pipzap.enable_hotkey.value:
319                         self["pipzapActions"] = HelpableActionMap(self, "pipzapActions",
320                                 {
321                                         "switchPiP": (self.togglePipzap, _("zap in pip window...")),
322                                 })
323 InfoBarPiP.baseInit = InfoBarPiP.__init__
324 InfoBarPiP.__init__ = InfoBarPiP__init__
325
326 def InfoBarPiP_getTogglePipzapName(self):
327         slist = self.servicelist
328         if slist and slist.dopipzap:
329                 return _("Zap focus to main screen")
330         return _("Zap focus to Picture in Picture")
331 InfoBarPiP.getTogglePipzapName = InfoBarPiP_getTogglePipzapName
332
333 def InfoBarPiP_togglePipzap(self):
334         # supposed to fix some problems with permanent timeshift patch
335         if isinstance(self, InfoBarTimeshift) and isinstance(self, InfoBarSeek) and \
336                 self.timeshift_enabled and self.isSeekable():
337                         return 0
338
339         if not self.session.pipshown:
340                 self.showPiP()
341         slist = self.servicelist
342         if slist:
343                 slist.togglePipzap()
344 InfoBarPiP.togglePipzap = InfoBarPiP_togglePipzap
345
346 # Using the base implementation would cause nasty bugs, so ignore it here
347 def InfoBarPiP_showPiP(self):
348         if self.session.pipshown:
349                 slist = self.servicelist
350                 if slist and slist.dopipzap:
351                         slist.togglePipzap()
352                 del self.session.pip
353                 self.session.pipshown = False
354         else:
355                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
356                 self.session.pip.show()
357                 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
358                 if self.session.pip.playService(newservice):
359                         self.session.pipshown = True
360                         self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
361                 else:
362                         self.session.pipshown = False
363                         del self.session.pip
364 InfoBarPiP.showPiP = InfoBarPiP_showPiP
365
366 # Using the base implementation would cause nasty bugs, so ignore it here
367 def InfoBarPiP_swapPiP(self):
368         swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
369         pipref = self.session.pip.getCurrentService()
370         if pipref and swapservice and pipref.toString() != swapservice.toString():
371                         self.session.pip.playService(swapservice)
372
373                         slist = self.servicelist
374                         if slist:
375                                 # TODO: this behaves real bad on subservices
376                                 if slist.dopipzap:
377                                         slist.servicelist.setCurrent(swapservice)
378                                 else:
379                                         slist.servicelist.setCurrent(pipref)
380
381                                 slist.addToHistory(pipref) # add service to history
382                                 slist.lastservice.value = pipref.toString() # save service as last playing one
383                         self.session.nav.stopService() # stop portal
384                         self.session.nav.playService(pipref) # start subservice
385 InfoBarPiP.swapPiP = InfoBarPiP_swapPiP
386
387 #pragma mark -
388 #pragma mark Picture in Picture
389 #pragma mark -
390
391 class PictureInPictureZapping(Screen):
392         skin = """<screen name="PictureInPictureZapping" flags="wfNoBorder" position="50,50" size="90,26" title="PiPZap" zPosition="-1">
393                 <eLabel text="PiP-Zap" position="0,0" size="90,26" foregroundColor="#00ff66" font="Regular;26" />
394         </screen>"""
395
396 def PictureInPicture__init__(self, session, *args, **kwargs):
397         PictureInPicture.baseInit(self, session, *args, **kwargs)
398         self.pipActive = session.instantiateDialog(PictureInPictureZapping)
399 PictureInPicture.baseInit = PictureInPicture.__init__
400 PictureInPicture.__init__ = PictureInPicture__init__
401
402 def PictureInPicture_active(self):
403         self.pipActive.show()
404 PictureInPicture.active = PictureInPicture_active
405
406 def PictureInPicture_inactive(self):
407         self.pipActive.hide()
408 PictureInPicture.inactive = PictureInPicture_inactive
409
410 #pragma mark -
411 #pragma mark Plugin
412 #pragma mark -
413
414 from PipzapSetup import PipzapSetup
415
416 # XXX: disabling more than the hotkey does not make much sense, because then you could just remove the plugin
417 config.plugins.pipzap = ConfigSubsection()
418 config.plugins.pipzap.enable_hotkey = ConfigEnableDisable(default = True)
419
420 def main(session):
421         session.open(PipzapSetup)
422
423 def Plugins(**kwargs):
424         return [
425                 PluginDescriptor(
426                         name="pipzap",
427                         description=_("Configure pipzap Plugin"),
428                         where=PluginDescriptor.WHERE_PLUGINMENU,
429                         fnc=main,
430                         needsRestart=True, # XXX: force restart for now as I don't think the plugin will work properly without one
431                 ),
432         ]