DreamMediathek Play Web and ipTV streams, example xml
[enigma2-plugins.git] / dreammediathek / src / MoviePlayer.py
1 # -*- coding: UTF-8 -*-
2 from Plugins.Plugin import PluginDescriptor
3 from Tools.BoundFunction import boundFunction
4 from Screens.MessageBox import MessageBox
5 from Screens.Screen import Screen
6 from Screens.ChoiceBox import ChoiceBox
7 from Components.ActionMap import ActionMap, NumberActionMap
8 from Components.Sources.StaticText import StaticText
9 from Components.Sources.List import List
10 from Components.AVSwitch import AVSwitch
11 from Components.config import config, Config, ConfigSelection, ConfigSubsection, ConfigText, getConfigListEntry, ConfigYesNo, ConfigIP, ConfigNumber,ConfigLocations
12 from Components.config import KEY_DELETE, KEY_BACKSPACE, KEY_LEFT, KEY_RIGHT, KEY_HOME, KEY_END, KEY_TOGGLEOW, KEY_ASCII, KEY_TIMEOUT
13 from Components.ConfigList import ConfigListScreen
14 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
15
16 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_HDD, SCOPE_CURRENT_PLUGIN, SCOPE_CURRENT_SKIN
17 from Tools.LoadPixmap import LoadPixmap
18 from enigma import eTimer, quitMainloop,eListbox,ePoint, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad, eServiceCenter, iServiceInformation, eServiceReference,iSeekableService,iServiceInformation, iPlayableService, iPlayableServicePtr
19 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
20 from twisted.web import client
21 from twisted.internet import reactor
22 from time import time
23
24 from Screens.InfoBarGenerics import InfoBarShowHide, InfoBarSeek, InfoBarNotifications, InfoBarServiceNotifications
25
26 from ServiceXML import iWebTVStations
27
28 config.plugins.dreamMediathek = ConfigSubsection()
29 config.plugins.dreamMediathek.general = ConfigSubsection()
30 config.plugins.dreamMediathek.general.on_movie_stop = ConfigSelection(default = "ask", choices = [
31         ("ask", _("Ask user")), ("quit", _("Return to movie list")), ("playnext", _("Play next video")), ("playagain", _("Play video again")) ])
32 config.plugins.dreamMediathek.general.on_exit = ConfigSelection(default = "ask", choices = [
33         ("ask", _("Ask user")), ("quit", _("Return to movie list"))])
34
35
36 class dreamMediathekPlayer(Screen, InfoBarNotifications):
37         STATE_IDLE = 0
38         STATE_PLAYING = 1
39         STATE_PAUSED = 2
40         ENABLE_RESUME_SUPPORT = True
41         ALLOW_SUSPEND = True
42
43         skin = """<screen name="dreamMediathekPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="dreamMediathekPlayer" backgroundColor="transparent">
44                 <ePixmap position="0,0" pixmap="skin_default/info-bg_mp.png" zPosition="-1" size="720,160" />
45                 <ePixmap position="29,40" pixmap="skin_default/screws_mp.png" size="665,104" alphatest="on" />
46                 <ePixmap position="48,70" pixmap="skin_default/icons/mp_buttons.png" size="108,13" alphatest="on" />
47                 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" size="15,10" alphatest="on" />
48                 <widget source="session.CurrentService" render="Label" position="230,73" size="360,40" font="Regular;20" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
49                         <convert type="ServiceName">Name</convert>
50                 </widget>
51                 <widget source="session.CurrentService" render="Label" position="580,73" size="90,24" font="Regular;20" halign="right" backgroundColor="#4e5a74" transparent="1">
52                         <convert type="ServicePosition">Length</convert>
53                 </widget>
54                 <widget source="session.CurrentService" render="Label" position="205,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
55                         <convert type="ServicePosition">Position</convert>
56                 </widget>
57                 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" foregroundColor="#20224f">
58                         <convert type="ServicePosition">Gauge</convert>
59                 </widget>
60                 <widget source="session.CurrentService" render="Label" position="576,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
61                         <convert type="ServicePosition">Remaining</convert>
62                 </widget>
63                 </screen>"""
64
65         def __init__(self, session, service, lastservice, infoCallback = None, nextCallback = None, prevCallback = None):
66                 Screen.__init__(self, session)
67                 InfoBarNotifications.__init__(self)
68                 self.session = session
69                 self.service = service
70                 self.infoCallback = infoCallback
71                 self.nextCallback = nextCallback
72                 self.prevCallback = prevCallback
73                 self.screen_timeout = 5000
74                 self.nextservice = None
75
76                 print "evEOF=%d" % iPlayableService.evEOF
77                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
78                         {
79                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
80                                 iPlayableService.evStart: self.__serviceStarted,
81                                 iPlayableService.evEOF: self.__evEOF,
82                         })
83                 
84                 self["actions"] = ActionMap(["OkCancelActions", "InfobarSeekActions", "MediaPlayerActions", "MovieSelectionActions"],
85                 {
86                                 "ok": self.ok,
87                                 "cancel": self.leavePlayer,
88                                 "stop": self.leavePlayer,
89                                 "playpauseService": self.playpauseService,
90                                 "seekFwd": self.playNextFile,
91                                 "seekBack": self.playPrevFile,
92                                 "showEventInfo": self.showVideoInfo,
93                         }, -2)
94
95
96                 self.lastservice = lastservice
97
98                 self.hidetimer = eTimer()
99                 self.hidetimer.timeout.get().append(self.ok)
100                 self.returning = False
101
102                 self.state = self.STATE_PLAYING
103                 self.lastseekstate = self.STATE_PLAYING
104
105                 self.onPlayStateChanged = [ ]
106                 self.__seekableStatusChanged()
107         
108                 self.play()
109                 self.onClose.append(self.__onClose)
110                 
111         def __onClose(self):
112                 self.session.nav.stopService()
113
114         def __evEOF(self):
115                 print "evEOF=%d" % iPlayableService.evEOF
116                 print "Event EOF"
117                 self.handleLeave(config.plugins.dreamMediathek.general.on_movie_stop.value)
118
119         def __setHideTimer(self):
120                 self.hidetimer.start(self.screen_timeout)
121
122         def showInfobar(self):
123                 self.show()
124                 if self.state == self.STATE_PLAYING:
125                         self.__setHideTimer()
126                 else:
127                         pass
128
129         def hideInfobar(self):
130                 self.hide()
131                 self.hidetimer.stop()
132
133         def ok(self):
134                 if self.shown:
135                         self.hideInfobar()
136                 else:
137                         self.showInfobar()
138
139         def showVideoInfo(self):
140                 if self.shown:
141                         self.hideInfobar()
142                 if self.infoCallback is not None:       
143                         self.infoCallback()
144
145
146         def playNextFile(self):
147                 print "playNextFile"
148                 if self.nextCallback() is not None:
149                         nextservice,error = self.nextCallback()
150                         print "nextservice--->",nextservice
151                         if nextservice is None:
152                                 self.handleLeave(config.plugins.dreamMediathek.general.on_movie_stop.value, error)
153                         else:
154                                 self.playService(nextservice)
155                                 self.showInfobar()
156
157         def playPrevFile(self):
158                 print "playPrevFile"
159                 if self.prevCallback() is not None:
160                         prevservice,error = self.prevCallback()
161                         if prevservice is None:
162                                 self.handleLeave(config.plugins.dreamMediathek.general.on_movie_stop.value, error)
163                         else:
164                                 self.playService(prevservice)
165                                 self.showInfobar()
166
167         def playagain(self):
168                 print "playagain"
169                 if self.state != self.STATE_IDLE:
170                         self.stopCurrent()
171                 self.play()
172         
173         def playService(self, newservice):
174                 if self.state != self.STATE_IDLE:
175                         self.stopCurrent()
176                 self.service = newservice
177                 self.play()
178
179         def play(self):
180                 if self.state == self.STATE_PAUSED:
181                         if self.shown:
182                                 self.__setHideTimer()   
183                 self.state = self.STATE_PLAYING
184                 self.session.nav.playService(self.service)
185                 if self.shown:
186                         self.__setHideTimer()
187
188         def stopCurrent(self):
189                 print "stopCurrent"
190                 self.session.nav.stopService()
191                 self.state = self.STATE_IDLE
192
193         def playpauseService(self):
194                 print "playpauseService"
195                 if self.state == self.STATE_PLAYING:
196                         self.pauseService()
197                 elif self.state == self.STATE_PAUSED:
198                         self.unPauseService()
199
200         def pauseService(self):
201                 print "pauseService"
202                 if self.state == self.STATE_PLAYING:
203                         self.setSeekState(self.STATE_PAUSED)
204                 
205         def unPauseService(self):
206                 print "unPauseService"
207                 if self.state == self.STATE_PAUSED:
208                         self.setSeekState(self.STATE_PLAYING)
209
210
211         def getSeek(self):
212                 service = self.session.nav.getCurrentService()
213                 if service is None:
214                         return None
215
216                 seek = service.seek()
217
218                 if seek is None or not seek.isCurrentlySeekable():
219                         return None
220
221                 return seek
222
223         def isSeekable(self):
224                 if self.getSeek() is None:
225                         return False
226                 return True
227
228         def __seekableStatusChanged(self):
229                 print "seekable status changed!"
230                 if not self.isSeekable():
231                         self.setSeekState(self.STATE_PLAYING)
232                 else:
233                         print "seekable"
234
235         def __serviceStarted(self):
236                 self.state = self.STATE_PLAYING
237                 self.__seekableStatusChanged()
238
239         def setSeekState(self, wantstate):
240                 print "setSeekState"
241                 if wantstate == self.STATE_PAUSED:
242                         print "trying to switch to Pause- state:",self.STATE_PAUSED
243                 elif wantstate == self.STATE_PLAYING:
244                         print "trying to switch to playing- state:",self.STATE_PLAYING
245                 service = self.session.nav.getCurrentService()
246                 if service is None:
247                         print "No Service found"
248                         return False
249                 pauseable = service.pause()
250                 if pauseable is None:
251                         print "not pauseable."
252                         self.state = self.STATE_PLAYING
253
254                 if pauseable is not None:
255                         print "service is pausable"
256                         if wantstate == self.STATE_PAUSED:
257                                 print "WANT TO PAUSE"
258                                 pauseable.pause()
259                                 self.state = self.STATE_PAUSED
260                                 if not self.shown:
261                                         self.hidetimer.stop()
262                                         self.show()
263                         elif wantstate == self.STATE_PLAYING:
264                                 print "WANT TO PLAY"
265                                 pauseable.unpause()
266                                 self.state = self.STATE_PLAYING
267                                 if self.shown:
268                                         self.__setHideTimer()
269
270                 for c in self.onPlayStateChanged:
271                         c(self.state)
272                 
273                 return True
274
275         def handleLeave(self, how, error = False):
276                 self.is_closing = True
277                 if how == "ask":
278                         list = (
279                                 (_("Yes"), "quit"),
280                                 (_("No, but play video again"), "playagain"),
281                                 (_("Yes, but play next video"), "playnext"),
282                                 (_("Yes, but play previous video"), "playprev"),
283                         )
284                         if error is False:
285                                 self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Stop playing this movie?"), list = list)
286                         else:
287                                 self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("No playable video found! Stop playing this movie?"), list = list)
288                 else:
289                         self.leavePlayerConfirmed([True, how])
290
291         def leavePlayer(self):
292                 self.handleLeave(config.plugins.dreamMediathek.general.on_movie_stop.value)
293
294         def leavePlayerConfirmed(self, answer):
295                 answer = answer and answer[1]
296                 if answer == "quit":
297                         self.close()
298                 elif answer == "playnext":
299                         self.playNextFile()
300                 elif answer == "playprev":
301                         self.playPrevFile()
302                 elif answer == "playagain":
303                         self.playagain()
304                         
305         def doEofInternal(self, playing):
306                 if not self.execing:
307                         return
308                 if not playing :
309                         return
310                 self.handleLeave(config.usage.on_movie_eof.value)
311