fix file permissions of non-executable files
[enigma2-plugins.git] / vlcplayer / src / VlcPlayer.py
1 # -*- coding: ISO-8859-1 -*-
2 #===============================================================================
3 # VLC Player Plugin by A. Lätsch 2007
4 #                   modified by Volker Christian 2008
5 #
6 # This is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free
8 # Software Foundation; either version 2, or (at your option) any later
9 # version.
10 #===============================================================================
11
12
13 from time import time
14
15 from enigma import iPlayableServicePtr
16 from enigma import iPlayableService
17 from enigma import iServiceInformation
18 from enigma import iSeekableService
19 from enigma import eServiceReference
20 from enigma import eServiceCenter
21 from enigma import eTimer
22 from Screens.Screen import Screen
23 from Screens.MessageBox import MessageBox
24 from Screens.MinuteInput import MinuteInput
25 from Screens.InfoBarGenerics import InfoBarNotifications, InfoBarAudioSelection
26 from Components.Sources.Source import Source
27 from Components.ServiceEventTracker import ServiceEventTracker
28 from Components.ActionMap import ActionMap
29 from Components.config import config
30
31
32 def isValidServiceId(id):
33         testSRef = eServiceReference(id, 0, "Just a TestReference")
34         info = eServiceCenter.getInstance().info(testSRef)
35         return info is not None
36
37 ENIGMA_SERVICEGS_ID = 0x1001
38 ENIGMA_SERVICETS_ID = 0x1002
39
40 ENIGMA_SERVICE_ID = 0
41
42 print "[VLC] Checking for buildin servicets ... ",
43 if isValidServiceId(ENIGMA_SERVICETS_ID):
44         print "yes"
45         ENIGMA_SERVICE_ID = ENIGMA_SERVICETS_ID
46         STOP_BEFORE_UNPAUSE = False
47 else:
48         print "no"
49         print "[VLC] Checking for existing and usable servicets.so ... ",
50         try:
51                 import servicets
52         except Exception, e:
53                 print e
54                 print "[VLC] Checking for usable gstreamer service ... ",
55                 if isValidServiceId(ENIGMA_SERVICEGS_ID):
56                         print "yes"
57                         ENIGMA_SERVICE_ID = ENIGMA_SERVICEGS_ID
58                         STOP_BEFORE_UNPAUSE = True
59                 else:
60                         print "no"
61                         print "[VLC] No valid VLC-Service found - VLC-streaming not supported"
62         else:
63                 print "yes"
64                 ENIGMA_SERVICE_ID = ENIGMA_SERVICETS_ID
65                 STOP_BEFORE_UNPAUSE = False
66
67 DEFAULT_VIDEO_PID = 0x44
68 DEFAULT_AUDIO_PID = 0x45
69
70
71 def isDvdUrl(url):
72         return url.startswith("dvd://") or url.startswith("dvdsimple://")
73
74
75 def splitDvdUrl(url):
76         pos = url.rfind("@", len(url)-8)
77         if pos > 0:
78                 track = url[pos+1:]
79                 url = url[0:pos]
80                 if track.find(":") >= 0:
81                         track, chapter = track.split(":")
82                 else:
83                         chapter = None
84         else:
85                 track, chapter = (None, None)
86         return (url, track, chapter)
87
88
89 class VlcService(Source, iPlayableServicePtr, iSeekableService):
90         refreshInterval = 3000
91
92         class Info(iServiceInformation):
93                 def __init__(self, name=""):
94                         self.name = name
95
96                 def getName(self):
97                         return self.name
98
99                 def getInfoObject(self, *args, **kwargs):
100                         return { }
101
102                 def getInfo(self, what):
103                         return -1
104
105                 def getInfoString(self, *args, **kwargs):
106                         return self.name
107
108                 def isPlayable(self):
109                         return True
110
111                 def getEvent(self, what):
112                         return None
113
114         def __init__(self, player):
115                 Source.__init__(self)
116                 self.__info = VlcService.Info()
117                 self.server = None
118                 self.service = self
119                 self.player = player
120                 self.lastrefresh = time()
121                 self.stats = None
122
123         def setName(self, name):
124                 i = name.rfind("/")
125                 if i >= 0:
126                         name = name[i+1:]
127                 i = name.rfind("\\")
128                 if i >= 0:
129                         name = name[i+1:]
130                 self.__info.name = name
131                 self.setChanged()
132
133         def setChanged(self):
134                 self.changed( (self.CHANGED_SPECIFIC, iPlayableService.evStart) )
135
136         def setServer(self, server):
137                 self.server = server
138
139         def __onRefresh(self):
140                 if self.server is None:
141                         self.stats = None
142                         return
143                 print "[VLC] refresh"
144                 try:
145                         self.stats = self.server.status()
146                         self.lastrefresh = time()
147                         if self.stats and self.stats.has_key("time"):
148                                 print "Time: ", self.stats["time"]
149                 except Exception, e:
150                         print e
151
152         def refresh(self):
153                 self.__onRefresh()
154
155         def info(self):
156                 return self.__info
157
158         # iSeekableService
159         def seek(self):
160                 return self
161
162         def getPlayPosition(self):
163                 if self.stats and self.stats.has_key("time"):
164                         pos = float(self.stats["time"])
165                         if self.player.state == VlcPlayer.STATE_PLAYING:
166                                 pos += time() - self.lastrefresh
167                         return (False, int(pos*90000))
168                 else:
169                         return (True, 0)
170
171         def getLength(self):
172                 if self.stats and self.stats.has_key("length"):
173                         return (False, int(self.stats["length"])*90000)
174                 else:
175                         return (True, 0)
176
177         # iPlayableService
178         def cueSheet(self): return None
179         def pause(self): return self.player
180         def audioTracks(self):
181                 return self.player.audioTracks()
182
183         def audioChannel(self): return None
184         def subServices(self): return None
185         def frontendInfo(self): return None
186         def timeshift(self): return None
187         def subtitle(self): return None
188         def audioDelay(self): return None
189         def rdsDecoder(self): return None
190         def stream(self): return None
191         def start(self):
192                 self.player.play()
193         def stop(self):
194                 self.player.stop()
195
196
197 class VlcPlayerSummary(Screen):
198         skin = """
199         <screen name="InfoBarMoviePlayerSummary" position="0,0" size="132,64">
200                 <widget source="session.CurrentService" render="Label" position="6,0" size="120,25" font="Regular;14" halign="center" valign="center" >
201                         <convert type="ServiceName">Name</convert>
202                 </widget>
203                 <widget source="session.CurrentService" render="Progress" position="16,27" size="100,5" borderWidth="1">
204                         <convert type="ServicePosition">Position</convert>
205                 </widget>
206                 <widget source="global.CurrentTime" render="Label" position="6,32" size="120,32" font="Regular;32" halign="center" valign="center">
207                         <convert type="ClockToText">Format:%H:%M</convert>
208                 </widget>
209                 <widget source="session.RecordState" render="FixedLabel" text=" " position="6,32" zPosition="1" size="120,32">
210                         <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
211                         <convert type="ConditionalShowHide">Blink</convert>
212                 </widget>
213         </screen>"""
214
215         def __init__(self, session, parent):
216                 Screen.__init__(self, session)
217                 self.skinName = "InfoBarMoviePlayerSummary"
218                 
219
220 class VlcPlayer(Screen, InfoBarNotifications, InfoBarAudioSelection):
221         screen_timeout = 5000
222
223         STATE_IDLE = 0
224         STATE_PLAYING = 1
225         STATE_PAUSED = 2
226
227         def __init__(self, session, server, currentList):
228                 Screen.__init__(self, session)
229                 InfoBarNotifications.__init__(self)
230                 InfoBarAudioSelection.__init__(self)
231                 self.server = server
232                 self.currentList = currentList
233                 self.skinName = "MoviePlayer"
234                 self.state = self.STATE_IDLE
235                 self.oldservice = self.session.screen["CurrentService"]
236                 self.oldNavService = self.session.nav.getCurrentlyPlayingServiceReference()
237                 self.session.nav.stopService()
238                 self.vlcservice = VlcService(self)
239                 self.session.screen["CurrentService"] = self.vlcservice
240                 self.hidetimer = eTimer()
241                 self.hidetimer.timeout.get().append(self.ok)
242                 self.onClose.append(self.__onClose)
243
244                 class VlcPlayerActionMap(ActionMap):
245                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
246                                 ActionMap.__init__(self, contexts, actions, prio)
247                                 self.player = player
248
249                         def action(self, contexts, action):
250                                 if action[:5] == "seek:":
251                                         time = int(action[5:])
252                                         self.player.seekRelative(time)
253                                         return 1
254                                 elif action[:8] == "seekdef:":
255                                         key = int(action[8:])
256                                         time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
257                                                         -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
258                                                         -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
259                                         self.player.seekRelative(time)
260                                         return 1
261                                 else:
262                                         return ActionMap.action(self, contexts, action)
263
264                 self["actions"] = VlcPlayerActionMap(self, ["OkCancelActions", "TvRadioActions", "InfobarSeekActions", "MediaPlayerActions"],
265                 {
266                                 "ok": self.ok,
267                                 "cancel": self.stop,
268                                 "keyTV": self.stop,
269                                 "pauseService": self.pause,
270                                 "unPauseService": self.play,
271                                 "play": self.play,
272                                 "seekFwd": self.seekFwd,
273                                 "seekBack": self.seekBack,
274                                 "seekFwdDown": self.seekFwd,
275                                 "seekBackDown": self.seekBack,
276                                 "seekFwdManual": self.seekManual,
277                                 "seekBackManual": self.seekManual,
278                                 "next": self.playNextFile,
279                                 "previous": self.playPrevFile
280                         }, -2)
281
282                 print "[VLC] evEOF=%d" % iPlayableService.evEOF
283                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
284                         {
285                                 iPlayableService.evEOF: self.__evEOF,
286                                 iPlayableService.evSOF: self.__evSOF
287                         })
288
289         def createSummary(self):
290                 print "[VLC] createSummary"
291                 return VlcPlayerSummary
292
293         def __onClose(self):
294                 self.session.screen["CurrentService"] = self.oldservice
295                 self.session.nav.playService(self.oldNavService)
296
297         def __evEOF(self):
298                 print "[VLC] Event EOF"
299                 self.stop()
300
301         def __evSOF(self):
302                 print "[VLC] Event SOF"
303                 self.vlcservice.refresh()
304
305         def playfile(self, path, name):
306                 if self.state != self.STATE_IDLE:
307                         self.stopCurrent()
308                 self.filename = path
309                 self.vlcservice.setName(name)
310                 self.play()
311
312         def play(self):
313                 if self.state == self.STATE_PLAYING:
314                         return
315                 if self.state == self.STATE_PAUSED:
316                         self.unpause()
317                         return
318                 print "[VLC] setupStream: " + self.filename
319                 if ENIGMA_SERVICE_ID == 0:
320                         self.hide()
321                         self.session.open(
322                                         MessageBox, _("No valid Enigma-Service to play a VLC-Stream\nCheck your installation and try again!"), MessageBox.TYPE_ERROR
323                         )
324                         self.close()
325                         return
326                 try:
327                         url = self.server.playFile(self.filename, DEFAULT_VIDEO_PID, DEFAULT_AUDIO_PID)
328                         print "[VLC] url: " + url
329                 except Exception, e:
330                         self.hide()
331                         self.session.open(
332                                         MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
333                         )
334                         self.close()
335                         return
336                 if url is not None:
337                         sref = eServiceReference(ENIGMA_SERVICE_ID, 0, url)
338                         print "sref valid=", sref.valid()
339                         sref.setData(0, DEFAULT_VIDEO_PID)
340                         sref.setData(1, DEFAULT_AUDIO_PID)
341                         self.session.nav.playService(sref)
342                         self.state = self.STATE_PLAYING
343                         if self.shown:
344                                 self.__setHideTimer()
345                         self.vlcservice.setServer(self.server)
346
347         def pause(self):
348                 print "[VLC] pause"
349                 if self.state == self.STATE_PLAYING:
350                         self.session.nav.pause(True)
351                         self.server.pause()
352                         self.state = self.STATE_PAUSED
353                         self.vlcservice.refresh()
354                         if not self.shown:
355                                 self.hidetimer.stop()
356                                 self.show()
357                 elif self.state == self.STATE_PAUSED:
358                         self.unpause()
359
360         def unpause(self):
361                 print "[VLC] unpause"
362                 try:
363                         self.server.seek("-2")
364                         self.server.unpause()
365                 except Exception, e:
366                         self.session.open(
367                                 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
368                         )
369                         self.stop()
370                         return
371                 if STOP_BEFORE_UNPAUSE:
372                         self.session.nav.stopService()
373                         sref = self.session.nav.getCurrentlyPlayingServiceReference()
374                         sref.setData(0, DEFAULT_VIDEO_PID)
375                         sref.setData(1, DEFAULT_AUDIO_PID)
376                         self.session.nav.playService(sref)
377                 else:
378                         self.session.nav.pause(False)
379                 self.state = self.STATE_PLAYING
380                 self.vlcservice.refresh()
381                 if self.shown:
382                         self.__setHideTimer()
383
384         def stopCurrent(self):
385                 print "[VLC] stopCurrent"
386                 self.session.nav.stopService()
387                 if self.state == self.STATE_IDLE:
388                         self.close()
389                         return
390                 try:
391                         self.server.stop()
392                         self.server.deleteCurrentTree()
393                 except Exception, e:
394                         self.session.open(
395                                 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
396                         )
397                 self.state = self.STATE_IDLE
398                 self.vlcservice.setServer(None)
399                 self.vlcservice.refresh()
400
401         def stop(self):
402                 print "[VLC] stop"
403                 self.stopCurrent()
404                 self.close()
405
406         def __setHideTimer(self):
407                 self.hidetimer.start(self.screen_timeout)
408
409         def showInfobar(self):
410                 self.vlcservice.refresh()
411                 self.show()
412                 if self.state == self.STATE_PLAYING:
413                         self.__setHideTimer()
414                 else:
415                         pass
416
417         def hideInfobar(self):
418                 self.hide()
419                 self.hidetimer.stop()
420
421         def ok(self):
422                 if self.shown:
423                         self.hideInfobar()
424                 else:
425                         self.showInfobar()
426
427         def playNextFile(self):
428                 print "[VLC] playNextFile"
429                 if isDvdUrl(self.filename):
430                         url, track, chapter = splitDvdUrl(self.filename)
431                         if track is None:
432                                 track = 1
433                         else:
434                                 track = int(track)
435                         if chapter is None:
436                                 chapter = 2
437                         else:
438                                 chapter = int(chapter) + 1
439                         url = "%s@%d:%d" % (url, track, chapter)
440                         self.playfile(url, "DVD")
441                         self.showInfobar()
442                 else:
443                         if self.currentList != None:
444                                 media, name = self.currentList.getNextFile()
445                                 if media is None:
446                                         self.session.open(
447                                                         MessageBox, _("No more files in this directory"), MessageBox.TYPE_INFO
448                                         )
449                                         self.close()
450                                 else:
451                                         self.playfile(media, name)
452                                         self.showInfobar()
453
454         def playPrevFile(self):
455                 print "[VLC] playPrevFile"
456                 if isDvdUrl(self.filename):
457                         url, track, chapter = splitDvdUrl(self.filename)
458                         if track is None:
459                                 track = 1
460                         else:
461                                 track = int(track)
462                         if chapter is not None and int(chapter) > 1:
463                                 chapter = int(chapter) - 1
464                         else:
465                                 chapter = 1
466                         url = "%s@%d:%d" % (url, track, chapter)
467                         self.playfile(url, "DVD")
468                         self.showInfobar()
469                 else:
470                         if self.currentList != None:
471                                 media, name = self.currentList.getPrevFile()
472                                 if media is None:
473                                         self.session.open(
474                                                         MessageBox, _("No previous file in this directory"), MessageBox.TYPE_INFO
475                                         )
476                                         self.close()
477                                 else:
478                                         self.playfile(media, name)
479                                         self.showInfobar()
480
481         def audioTracks(self):
482                 return self.session.nav.getCurrentService() and self.session.nav.getCurrentService().audioTracks();
483
484         def seekRelative(self, delta):
485                 """delta is seconds as integer number
486                 positive=forwards, negative=backwards"""
487                 if self.state != self.STATE_IDLE:
488                         if (delta >= 0):
489                                 self.server.seek("+" + str(delta))
490                         else:
491                                 self.server.seek(str(delta))
492                 self.showInfobar()
493
494         def seekFwd(self):
495                 if isDvdUrl(self.filename):
496                         url, track, chapter = splitDvdUrl(self.filename)
497                         if track is None:
498                                 track = 2
499                         else:
500                                 track = int(track) + 1
501                         url = "%s@%d" % (url, track)
502                         self.playfile(url, "DVD")
503                         self.showInfobar()
504                 else:
505                         self.seekRelative(600)
506
507         def seekBack(self):
508                 if isDvdUrl(self.filename):
509                         url, track, chapter = splitDvdUrl(self.filename)
510                         if track is not None and int(track) > 2:
511                                 track = int(track) - 1
512                                 url = "%s@%d" % (url, track)
513                         else:
514                                 track = 1
515                         self.playfile(url, "DVD")
516                         self.showInfobar()
517                 else:
518                         self.seekRelative(-600)
519
520         def seekToMinute(self, minutes):
521                 self.server.seek(str(int(minutes)*60))
522                 self.showInfobar()
523
524         def seekManual(self):
525                 self.session.openWithCallback(self.seekToMinute, MinuteInput)