1 # -*- coding: ISO-8859-1 -*-
2 #===============================================================================
3 # VLC Player Plugin by A. Lätsch 2007
4 # modified by Volker Christian 2008
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
10 #===============================================================================
15 from sys import maxint
16 from random import randint, seed
17 from urllib import urlencode
18 from urllib2 import urlopen
19 from xml.dom.minidom import parse
20 from VlcPlayer import VlcPlayer, isDvdUrl
27 path = path.replace("\\","/").replace("//", "/")
30 if len(path) > 0 and path[0] != '/':
31 path = posixpath.normpath('/' + path)[1:]
33 path = posixpath.normpath(path)
35 if len(path) == 0 or path == "//":
43 def __init__(self, cfg):
50 return self.cfg.name.value
55 def getAddressType(self):
56 return self.cfg.addressType.value
58 def addressType(self):
59 return self.cfg.addressType
62 return self.cfg.hostip.tostring(self.cfg.hostip.value)
65 return self.cfg.hostip
67 def getHttpPort(self):
68 return self.cfg.httpport.value
71 return self.cfg.httpport
74 return self.cfg.basedir.value
77 return self.cfg.basedir
79 def getVideoCodec(self):
80 return self.cfg.videocodec.value
83 return self.cfg.videocodec
85 def getVideoBitrate(self):
86 return self.cfg.videobitrate.value
88 def videoBitrate(self):
89 return self.cfg.videobitrate
91 def getAudioCodec(self):
92 return self.cfg.audiocodec.value
95 return self.cfg.audiocodec
97 def getAudioBitrate(self):
98 return self.cfg.audiobitrate.value
100 def audioBitrate(self):
101 return self.cfg.audiobitrate
103 def getSamplerate(self):
104 return self.cfg.samplerate.value
106 def samplerate(self):
107 return self.cfg.samplerate
109 def getAudioChannels(self):
110 return self.cfg.audiochannels.value
112 def audioChannels(self):
113 return self.cfg.audiochannels
115 def getVideoNorm(self):
116 return self.cfg.videonorm.value
119 return self.cfg.videonorm
121 def getOverscanCorrection(self):
122 return self.cfg.overscancorrection.value
124 def overscanCorrection(self):
125 return self.cfg.overscancorrection
127 def getSOverlay(self):
128 return self.cfg.soverlay.value
131 return self.cfg.soverlay
133 def getTranscodeVideo(self):
134 return self.cfg.transcodeVideo.value
136 def transcodeVideo(self):
137 return self.cfg.transcodeVideo
139 def getTranscodeAudio(self):
140 return self.cfg.transcodeAudio.value
142 def transcodeAudio(self):
143 return self.cfg.transcodeAudio
146 return self.cfg.dvdPath
148 def getDvdPath(self):
149 return self.cfg.dvdPath.value
151 def __xmlRequest(self, request, params):
152 uri = "/requests/" + request + ".xml"
153 if params is not None: uri = uri + "?" + urlencode(params).replace('+', '%20')
154 location = "%s:%d" % (self.getHost(), self.getHttpPort())
155 resp = urlopen("http://" + location + uri)
157 raise IOError, "No response from Server"
162 def getFilesAndDirs(self, directory, regex):
165 response = self.__xmlRequest("browse", {"dir": directory})
166 for element in response.getElementsByTagName("element"):
167 if element.hasAttribute("type"):
168 name = element.getAttribute("name").encode("utf8")
169 path = normpath(element.getAttribute("path").encode("utf8"))
171 elementType = element.getAttribute("type")
172 if elementType == "directory":
173 directories.append([name, path])
174 elif elementType == "file":
175 if regex is None or regex.search(path):
176 files.append([name, path])
177 return (files, directories)
179 def getPlaylistEntries(self):
180 xml = self.__xmlRequest("playlist", None)
182 for e in xml.getElementsByTagName("leaf"):
183 if e.hasAttribute("uri") is not None:
184 name = e.getAttribute("name").encode("utf8")
186 name = "..." + name[-50:]
187 path = e.getAttribute("uri").encode("utf8")
188 files.append([name, path])
191 def getCurrentElement(self):
192 xml = self.__xmlRequest("playlist", None)
193 for e in xml.getElementsByTagName("leaf"):
194 if e.hasAttribute("current"):
198 def play(self, session, media, name, currentList = None, player = None):
200 # or not isinstance(player, VlcPlayer):
202 dlg = session.open(player, self, currentList)
203 dlg.playfile(media, name)
206 def playFile(self, filename, videoPid, audioPid):
207 streamName = "dream" + str(randint(0, maxint))
210 doDirect = isDvdUrl(filename) or re.match("(?i).*\.(mpg|mpeg|ts)$", filename.lower())
212 if not doDirect or self.getTranscodeVideo():
213 videoNormList = self.getVideoNorm().split(",")
216 transcode.append("vcodec=%s,vb=%d,venc=ffmpeg{strict-rc=1},fps=%s" % (
\r
217 self.getVideoCodec(),self.getVideoBitrate(),
220 # Old canvas settings
\r
221 #transcode.append("width=%s,height=%s,canvas-width=%s,canvas-height=%s,canvas-aspect=%s" % (
\r
222 # str(int(float(videoNormList[0]) - float(videoNormList[0]) * float(self.getOverscanCorrection()) / 100)),
\r
223 # str(int(float(videoNormList[1]) - float(videoNormList[1]) * float(self.getOverscanCorrection()) / 100)),
\r
224 # videoNormList[0], videoNormList[1], videoNormList[2],
\r
227 #New canvas - since VLC 0.9
\r
228 transcode.append("vfilter=canvas{width=%s,height=%s,aspect=%s}" % (
\r
229 str(int(float(videoNormList[0]) - float(videoNormList[0]) * float(self.getOverscanCorrection()) / 100)),
230 str(int(float(videoNormList[1]) - float(videoNormList[1]) * float(self.getOverscanCorrection()) / 100)),
233 if self.getSOverlay():
234 transcode.append("soverlay")
235 if not doDirect or self.getTranscodeAudio():
236 transcode.append("acodec=%s,ab=%d,channels=%d,samplerate=%s" % (
237 self.getAudioCodec(),
238 self.getAudioBitrate(),
239 self.getAudioChannels(),
242 if re.match("[a-zA-Z]:", filename):
243 # Fix for subtitles with VLC on Windows.
244 filename = filename.replace("/", "\\")
246 filename = filename.replace("\\", "\\\\").replace("'", "\\'")
247 # input = filename + " :dvdread-caching=3000 :sub-track=1 :audio-track=1 :sout=#"
248 input = filename + " :sout=#"
250 if len(transcode) > 0:
251 input += "transcode{%s}:" % (",".join(transcode))
253 mux="ts{pid-video=%d,pid-audio=%d}" % (videoPid, audioPid)
254 input += "std{access=http,mux=%s,dst=/%s.ts} :sout-all :sout-keep" % (mux, streamName)
256 print "[VLC] playfile", input
258 xml = self.__xmlRequest("status", {"command": "in_play", "input": input})
259 error = xml.getElementsByTagName("error")
260 if error is not None and len(error) > 0:
261 self.lastError = getText(error[0].childNodes).strip()
262 if len(self.lastError) == 0:
263 self.lastError = None
265 print "[VLC] VlcControl error:", self.lastError
268 self.lastError = None
269 return "http://%s:%d/%s.ts" % (self.getHost(), self.getHttpPort(), streamName)
272 self.__xmlRequest("status", {"command": "pl_pause"})
275 self.__xmlRequest("status", {"command": "pl_stop"})
278 self.__xmlRequest("status", {"command": "pl_pause"})
280 def delete(self, id):
281 self.__xmlRequest("status", {"command": "pl_delete", "id": str(id)})
283 def deleteCurrentTree(self):
284 print "[VLC] delete current tree"
285 currentElement = self.getCurrentElement()
286 while currentElement is not None and currentElement.parentNode.getAttribute("ro") != "ro":
287 currentElement = currentElement.parentNode
288 id = int(currentElement.getAttribute("id"))
291 def seek(self, value):
292 """ Allowed values are of the form:
293 [+ or -][<int><H or h>:][<int><M or m or '>:][<int><nothing or S or s or ">]
295 (value between [ ] are optional, value between < > are mandatory)
297 1000 -> seek to the 1000th second
298 +1H:2M -> seek 1 hour and 2 minutes forward
299 -10% -> seek 10% back"""
300 self.__xmlRequest("status", {"command": "seek", "val": str(value)})
303 xml = self.__xmlRequest("status", None)
305 for e in xml.documentElement.childNodes:
306 if e.nodeType == e.ELEMENT_NODE:
307 if e.firstChild is None:
308 stats[e.nodeName.encode("latin_1", "replace")] = None
310 stats[e.nodeName.encode("latin_1", "replace")] = e.firstChild.nodeValue.encode("latin_1", "replace")
313 def loadPlaylist(self, playlist):
314 self.__xmlRequest("status", {"command": "in_play", "input": playlist})
315 self.__xmlRequest("status", {"command": "pl_stop"})
316 xml = self.__xmlRequest("playlist", None)
318 for n in xml.getElementsByTagName("node"):
319 if n.hasAttribute("name") is not None:
320 if n.getAttribute("name").encode("utf8", "replace") == playlist:
322 id = n.getAttribute("id")
323 elif int(id) < int(n.getAttribute("id")):
324 id = n.getAttribute("id")