1 from os import path as os_path, remove as os_remove, listdir as os_listdir, system
2 from enigma import eTimer, iPlayableService, iServiceInformation, eServiceReference, iServiceKeys
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications
8 from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
9 from Components.Label import Label
10 from Components.FileList import FileList
11 from Components.MenuList import MenuList
12 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
13 from Components.config import config
14 from Tools.Directories import pathExists, fileExists
15 from Components.Harddisk import harddiskmanager
17 import servicedvd # load c++ part of dvd player plugin
21 class FileBrowser(Screen):
23 <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
24 <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
26 def __init__(self, session, dvd_filelist = [ ]):
27 Screen.__init__(self, session)
29 self.dvd_filelist = dvd_filelist
31 self["filelist"] = MenuList(self.dvd_filelist)
34 if lastpath is not None:
35 currDir = lastpath + "/"
37 currDir = "/media/dvd/"
38 if not pathExists(currDir):
41 self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
42 self["filelist"] = self.filelist
44 self["FilelistActions"] = ActionMap(["OkCancelActions"],
51 if len(self.dvd_filelist):
52 print "OK " + self["filelist"].getCurrent()
53 self.close(self["filelist"].getCurrent())
56 filename = self["filelist"].getFilename()
57 if filename is not None:
58 if filename.upper().endswith("VIDEO_TS/"):
59 print "dvd structure found, trying to open..."
60 dvdpath = filename[0:-9]
61 lastpath = (dvdpath.rstrip("/").rsplit("/",1))[0]
62 print "lastpath video_ts/=", lastpath
65 if self["filelist"].canDescent(): # isDir
66 self["filelist"].descent()
67 pathname = self["filelist"].getCurrentDirectory() or ""
68 if fileExists(pathname+"VIDEO_TS.IFO"):
69 print "dvd structure found, trying to open..."
70 lastpath = (pathname.rstrip("/").rsplit("/",1))[0]
71 print "lastpath video_ts.ifo=", lastpath
74 lastpath = filename[0:filename.rfind("/")]
75 print "lastpath directory=", lastpath
81 class DVDSummary(Screen):
83 <screen position="0,0" size="132,64">
84 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
85 <convert type="ServiceName">Name</convert>
87 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
88 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
89 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
90 <convert type="ServicePosition">Position</convert>
92 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
93 <convert type="ServicePosition">Position</convert>
97 def __init__(self, session, parent):
98 Screen.__init__(self, session, parent)
100 self["DVDPlayer"] = Label("DVD Player")
101 self["Title"] = Label("")
102 self["Time"] = Label("")
103 self["Chapter"] = Label("")
105 def updateChapter(self, chapter):
106 self["Chapter"].setText(chapter)
108 def setTitle(self, title):
109 self["Title"].setText(title)
111 class DVDOverlay(Screen):
112 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
113 def __init__(self, session, args = None):
114 Screen.__init__(self, session)
116 class ChapterZap(Screen):
118 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
119 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
120 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
129 self.close(int(self["number"].getText()))
131 def keyNumberGlobal(self, number):
132 self.Timer.start(3000, True) #reset timer
133 self.field = self.field + str(number)
134 self["number"].setText(self.field)
135 if len(self.field) >= 4:
138 def __init__(self, session, number):
139 Screen.__init__(self, session)
140 self.field = str(number)
142 self["chapter"] = Label(_("Chapter:"))
144 self["number"] = Label(self.field)
146 self["actions"] = NumberActionMap( [ "SetupActions" ],
150 "1": self.keyNumberGlobal,
151 "2": self.keyNumberGlobal,
152 "3": self.keyNumberGlobal,
153 "4": self.keyNumberGlobal,
154 "5": self.keyNumberGlobal,
155 "6": self.keyNumberGlobal,
156 "7": self.keyNumberGlobal,
157 "8": self.keyNumberGlobal,
158 "9": self.keyNumberGlobal,
159 "0": self.keyNumberGlobal
162 self.Timer = eTimer()
163 self.Timer.callback.append(self.keyOK)
164 self.Timer.start(3000, True)
166 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen, InfoBarCueSheetSupport):
167 # ALLOW_SUSPEND = True
168 ENABLE_RESUME_SUPPORT = True
171 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
173 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
174 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
175 <!-- colorbuttons -->
176 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
178 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
179 <widget source="session.CurrentService" render="Label" position="230,73" size="300,22" font="Regular;20" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" noWrap="1">
180 <convert type="ServiceName">Name</convert>
182 <!-- Chapter info -->
183 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
184 <!-- Audio track info -->
185 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
186 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
187 <!-- Subtitle track info -->
188 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
189 <convert type="ServiceInfo">HasTelext</convert>
190 <convert type="ConditionalShowHide" />
192 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
193 <!-- Elapsed time -->
194 <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" >
195 <convert type="ServicePosition">Position,ShowHours</convert>
197 <!-- Progressbar (movie position)-->
198 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
199 <convert type="ServicePosition">Gauge</convert>
201 <!-- Remaining time -->
202 <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" >
203 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
207 def save_infobar_seek_config(self):
208 self.saved_config_speeds_forward = config.seek.speeds_forward.value
209 self.saved_config_speeds_backward = config.seek.speeds_backward.value
210 self.saved_config_enter_forward = config.seek.enter_forward.value
211 self.saved_config_enter_backward = config.seek.enter_backward.value
212 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
213 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
214 self.saved_config_seek_on_pause = config.seek.on_pause.value
215 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
217 def change_infobar_seek_config(self):
218 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
219 config.seek.speeds_backward.value = [8, 16, 32, 64]
220 config.seek.speeds_slowmotion.value = [ ]
221 config.seek.enter_forward.value = "2"
222 config.seek.enter_backward.value = "2"
223 config.seek.stepwise_minspeed.value = "Never"
224 config.seek.stepwise_repeat.value = "3"
225 config.seek.on_pause.value = "play"
227 def restore_infobar_seek_config(self):
228 config.seek.speeds_forward.value = self.saved_config_speeds_forward
229 config.seek.speeds_backward.value = self.saved_config_speeds_backward
230 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
231 config.seek.enter_forward.value = self.saved_config_enter_forward
232 config.seek.enter_backward.value = self.saved_config_enter_backward
233 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
234 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
235 config.seek.on_pause.value = self.saved_config_seek_on_pause
237 def __init__(self, session, dvd_device = None, dvd_filelist = [ ], args = None):
238 Screen.__init__(self, session)
239 InfoBarBase.__init__(self)
240 InfoBarNotifications.__init__(self)
241 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
242 InfoBarShowHide.__init__(self)
243 HelpableScreen.__init__(self)
244 self.save_infobar_seek_config()
245 self.change_infobar_seek_config()
246 InfoBarSeek.__init__(self, useSeekBackHack=False)
247 InfoBarPVRState.__init__(self)
248 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
250 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
251 self.session.nav.stopService()
252 self["audioLabel"] = Label("n/a")
253 self["subtitleLabel"] = Label("")
254 self["chapterLabel"] = Label("")
255 self.last_audioTuple = None
256 self.last_subtitleTuple = None
257 self.totalChapters = 0
258 self.currentChapter = 0
260 self.currentTitle = 0
262 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
264 iPlayableService.evStopped: self.__serviceStopped,
265 iPlayableService.evUser: self.__timeUpdated,
266 iPlayableService.evUser+1: self.__statePlay,
267 iPlayableService.evUser+2: self.__statePause,
268 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
269 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
270 iPlayableService.evUser+5: self.__osdStringAvail,
271 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
272 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
273 iPlayableService.evUser+8: self.__chapterUpdated,
274 iPlayableService.evUser+9: self.__titleUpdated,
275 iPlayableService.evUser+11: self.__menuOpened,
276 iPlayableService.evUser+12: self.__menuClosed
279 self["DVDPlayerDirectionActions"] = ActionMap(["DirectionActions"],
281 #MENU KEY DOWN ACTIONS
282 "left": self.keyLeft,
283 "right": self.keyRight,
285 "down": self.keyDown,
287 #MENU KEY REPEATED ACTIONS
288 "leftRepeated": self.doNothing,
289 "rightRepeated": self.doNothing,
290 "upRepeated": self.doNothing,
291 "downRepeated": self.doNothing,
294 "leftUp": self.doNothing,
295 "rightUp": self.doNothing,
296 "upUp": self.doNothing,
297 "downUp": self.doNothing,
300 self["OkCancelActions"] = ActionMap(["OkCancelActions"],
303 "cancel": self.keyCancel,
306 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
309 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
310 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
311 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
312 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
313 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
314 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
315 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
316 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
317 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
318 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
319 "seekBeginning": self.seekBeginning,
322 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
324 "1": self.keyNumberGlobal,
325 "2": self.keyNumberGlobal,
326 "3": self.keyNumberGlobal,
327 "4": self.keyNumberGlobal,
328 "5": self.keyNumberGlobal,
329 "6": self.keyNumberGlobal,
330 "7": self.keyNumberGlobal,
331 "8": self.keyNumberGlobal,
332 "9": self.keyNumberGlobal,
333 "0": self.keyNumberGlobal,
336 self.onClose.append(self.__onClose)
337 self.physicalDVD = False
338 self.dvd_device = None
340 self.dvd_device = dvd_device
341 self.physicalDVD = True
343 devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
344 if pathExists(devicepath):
345 from Components.Scanner import scanDevice
346 res = scanDevice(devicepath)
347 list = [ (r.description, r, res[r], self.session) for r in res ]
349 (desc, scanner, files, session) = list[0]
352 if file.mimetype == "video/x-dvd":
353 self.dvd_device = devicepath
354 print "physical dvd found:", self.dvd_device
355 self.physicalDVD = True
357 self.dvd_filelist = dvd_filelist
358 self.onFirstExecBegin.append(self.showFileBrowser)
361 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
362 self.old_policy = open("/proc/stb/video/policy", "r").read()
363 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
365 def keyNumberGlobal(self, number):
366 print "You pressed number " + str(number)
367 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
369 def numberEntered(self, retval):
370 # print self.servicelist
372 self.zapToNumber(retval)
374 def __serviceStopped(self):
375 self.dvdScreen.hide()
376 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
378 def serviceStarted(self): #override InfoBarShowHide function
379 self.dvdScreen.show()
380 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
382 def doEofInternal(self, playing):
386 def __menuOpened(self):
389 self["NumberActions"].setEnabled(False)
391 def __menuClosed(self):
394 self["NumberActions"].setEnabled(True)
396 def setChapterLabel(self):
398 chapterOSD = "DVD Menu"
399 if self.currentTitle > 0:
400 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
401 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
402 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
403 self["chapterLabel"].setText(chapterOSD)
405 self.session.summary.updateChapter(chapterLCD)
412 def toggleInfo(self):
417 def __timeUpdated(self):
420 def __statePlay(self):
423 def __statePause(self):
426 def __osdFFwdInfoAvail(self):
427 self.setChapterLabel()
428 print "FFwdInfoAvail"
430 def __osdFBwdInfoAvail(self):
431 self.setChapterLabel()
432 print "FBwdInfoAvail"
434 def __osdStringAvail(self):
437 def __osdAudioInfoAvail(self):
438 audioTuple = self.service.info().getInfoObject(iServiceInformation.sUser+6)
439 print "AudioInfoAvail ", repr(audioTuple)
441 audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
442 self["audioLabel"].setText(audioString)
443 if audioTuple != self.last_audioTuple and not self.in_menu:
445 self.last_audioTuple = audioTuple
447 def __osdSubtitleInfoAvail(self):
448 subtitleTuple = self.service.info().getInfoObject(iServiceInformation.sUser+7)
449 print "SubtitleInfoAvail ", repr(subtitleTuple)
452 if subtitleTuple[0] is not 0:
453 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
454 self["subtitleLabel"].setText(subtitleString)
455 if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
457 self.last_subtitleTuple = subtitleTuple
459 def __chapterUpdated(self):
460 self.currentChapter = self.service.info().getInfo(iServiceInformation.sCurrentChapter)
461 self.totalChapters = self.service.info().getInfo(iServiceInformation.sTotalChapters)
462 self.setChapterLabel()
463 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
465 def __titleUpdated(self):
466 self.currentTitle = self.service.info().getInfo(iServiceInformation.sCurrentTitle)
467 self.totalTitles = self.service.info().getInfo(iServiceInformation.sTotalTitles)
468 self.setChapterLabel()
469 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
473 def askLeavePlayer(self):
474 choices = [(_("Continue playing"), "play"), (_("Exit"), "exit")]
475 if not self.physicalDVD:
476 choices.insert(1,(_("Return to file browser"), "browser"))
477 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
479 def nextAudioTrack(self):
481 self.service.keys().keyPressed(iServiceKeys.keyUser)
483 def nextSubtitleTrack(self):
485 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
487 def enterDVDAudioMenu(self):
489 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
491 def nextChapter(self):
493 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
495 def prevChapter(self):
497 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
501 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
505 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
507 def enterDVDMenu(self):
509 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
511 def seekBeginning(self):
513 seekable = self.getSeek()
514 if seekable is not None:
517 def zapToNumber(self, number):
519 seekable = self.getSeek()
520 if seekable is not None:
521 print "seek to chapter %d" % number
522 seekable.seekChapter(number)
527 self.service.keys().keyPressed(iServiceKeys.keyRight)
531 self.service.keys().keyPressed(iServiceKeys.keyLeft)
535 self.service.keys().keyPressed(iServiceKeys.keyUp)
539 self.service.keys().keyPressed(iServiceKeys.keyDown)
545 self.service.keys().keyPressed(iServiceKeys.keyOk)
548 self.askLeavePlayer()
550 def showFileBrowser(self):
551 if self.physicalDVD and len(self.dvd_filelist) == 0:
552 if self.dvd_device == harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()):
553 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
555 self.DVDdriveCB(True)
556 elif len(self.dvd_filelist) == 1:
557 self.FileBrowserClosed(self.dvd_filelist[0])
559 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
561 def DVDdriveCB(self, answer):
563 self.FileBrowserClosed(self.dvd_device)
565 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
566 self.physicalDVD = False
568 def FileBrowserClosed(self, val):
569 curref = self.session.nav.getCurrentlyPlayingServiceReference()
570 print "FileBrowserClosed", val
572 self.askLeavePlayer()
574 newref = eServiceReference(4369, 0, val)
575 print "play", newref.toString()
576 if curref is None or curref != newref:
577 self.session.nav.playService(newref)
578 self.service = self.session.nav.getCurrentService()
579 print "self.service", self.service
580 print "cur_dlg", self.session.current_dialog
582 def exitCB(self, answer):
583 if answer is not None:
584 if answer[1] == "exit":
588 if answer[1] == "browser":
589 #TODO check here if a paused dvd playback is already running... then re-start it...
593 self.showFileBrowser()
598 for i in (("/proc/stb/video/aspect", self.old_aspect), ("/proc/stb/video/policy", self.old_policy), ("/proc/stb/denc/0/wss", self.old_wss)):
600 open(i[0], "w").write(i[1])
602 print "restore", i[0], "failed"
603 self.restore_infobar_seek_config()
604 self.session.nav.playService(self.oldService)
606 def playLastCB(self, answer): # overwrite infobar cuesheet function
607 print "playLastCB", answer, self.resume_point
609 seek = self.service.seek()
611 seek.seekTo(self.resume_point)
612 pause = self.service.pause()
614 self.hideAfterResume()
616 def showAfterCuesheetOperation(self):
620 def createSummary(self):
623 #override some InfoBarSeek functions
625 self.setSeekState(self.SEEK_STATE_PLAY)
627 def calcRemainingTime(self):
630 def main(session, **kwargs):
631 session.open(DVDPlayer)
633 def menu(menuid, **kwargs):
634 if menuid == "mainmenu":
635 return [(_("DVD Player"), main, "dvd_player", 46)]
638 from Plugins.Plugin import PluginDescriptor
640 def filescan_open(list, session, **kwargs):
641 if len(list) == 1 and list[0].mimetype == "video/x-dvd":
642 splitted = list[0].path.split('/')
643 print "splitted", splitted
644 if len(splitted) > 2:
645 if splitted[1] == 'autofs':
646 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
649 print "splitted[0]", splitted[1]
653 if x.mimetype == "video/x-dvd-iso":
654 dvd_filelist.append(x.path)
655 if x.mimetype == "video/x-dvd":
656 dvd_filelist.append(x.path.rsplit('/',1)[0])
657 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
659 def filescan(**kwargs):
660 from Components.Scanner import Scanner, ScanPath
662 # Overwrite checkFile to only detect local
663 class LocalScanner(Scanner):
664 def checkFile(self, file):
665 return fileExists(file.path)
668 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
671 ScanPath(path = "video_ts", with_subdirs = False),
672 ScanPath(path = "", with_subdirs = False),
675 description = "Play DVD",
676 openfnc = filescan_open,
679 def Plugins(**kwargs):
680 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
681 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]