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 urllib import urlopen
19 from xml.dom.minidom import parse
20 from VlcPlayer import 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 getVideoWidth(self):
116 return self.cfg.videowidth.value
118 def videoWidth(self):
119 return self.cfg.videowidth
121 def getVideoHeight(self):
122 return self.cfg.videoheight.value
124 def videoHeight(self):
125 return self.cfg.videoheight
127 def getFramesPerSecond(self):
128 return self.cfg.framespersecond.value
130 def framesPerSecond(self):
131 return self.cfg.framespersecond
133 def getAspectRatio(self):
134 return self.cfg.aspectratio.value
136 def aspectRatio(self):
137 return self.cfg.aspectratio
139 def getSOverlay(self):
140 return self.cfg.soverlay.value
143 return self.cfg.soverlay
145 def getTranscodeVideo(self):
146 return self.cfg.transcodeVideo.value
148 def transcodeVideo(self):
149 return self.cfg.transcodeVideo
151 def getTranscodeAudio(self):
152 return self.cfg.transcodeAudio.value
154 def transcodeAudio(self):
155 return self.cfg.transcodeAudio
158 return self.cfg.dvdPath
160 def getDvdPath(self):
161 return self.cfg.dvdPath.value
163 def __xmlRequest(self, request, params):
164 uri = "/requests/" + request + ".xml"
165 if params is not None: uri = uri + "?" + urlencode(params)
166 location = "%s:%d" % (self.getHost(), self.getHttpPort())
167 resp = urlopen("http://" + location + uri)
169 raise IOError, "No response from Server"
172 def getFilesAndDirs(self, directory, regex):
175 response = self.__xmlRequest("browse", {"dir": directory})
176 for element in response.getElementsByTagName("element"):
177 if element.hasAttribute("type"):
178 name = element.getAttribute("name").encode("utf8")
179 path = normpath(element.getAttribute("path").encode("utf8"))
181 elementType = element.getAttribute("type")
182 if elementType == "directory":
183 directories.append([name, path])
184 elif elementType == "file":
185 if regex is None or regex.search(path):
186 files.append([name, path])
187 return (files, directories)
189 def getPlaylistEntries(self):
190 xml = self.__xmlRequest("playlist", None)
192 for e in xml.getElementsByTagName("leaf"):
193 if e.hasAttribute("uri") is not None:
194 name = e.getAttribute("name").encode("utf8")
196 name = "..." + name[-50:]
197 path = e.getAttribute("uri").encode("utf8")
198 files.append([name, path])
201 def getCurrentElement(self):
202 xml = self.__xmlRequest("playlist", None)
203 for e in xml.getElementsByTagName("leaf"):
204 if e.hasAttribute("current"):
208 def playFile(self, filename, videoPid, audioPid):
209 streamName = "dream" + str(randint(0, maxint))
212 doDirect = isDvdUrl(filename) or re.match("(?i).*\.(mpg|mpeg|ts)$", filename)
214 if not doDirect or self.getTranscodeVideo():
215 transcode.append("vcodec=%s,vb=%d,venc=ffmpeg{strict-rc=1},width=%s,height=%s,fps=%s,scale=1" % (
216 self.getVideoCodec(),
217 self.getVideoBitrate(),
218 self.getVideoWidth(),
219 self.getVideoHeight(),
220 self.getFramesPerSecond()
222 if self.getAspectRatio() != "none":
223 transcode.append("canvas-width=%s,canvas-height=%s,canvas-aspect=%s" % (
224 self.getVideoWidth(),
225 self.getVideoHeight(),
226 self.getAspectRatio()
229 if not doDirect or self.getTranscodeAudio():
230 transcode.append("acodec=%s,ab=%d,channels=%d,samplerate=%s" % (
231 self.getAudioCodec(),
232 self.getAudioBitrate(),
233 self.getAudioChannels(),
237 if self.getSOverlay():
238 transcode.append("soverlay")
240 if re.match("[a-zA-Z]:", filename):
241 # Fix for subtitles with VLC on Windows.
242 filename = filename.replace("/", "\\")
244 filename = filename.replace("\\", "\\\\").replace("'", "\\'")
245 # input = filename + " :dvdread-caching=3000 :sub-track=1 :audio-track=1 :sout=#"
246 input = filename + " :sout=#"
248 if len(transcode) > 0:
249 input += "transcode{%s}:" % (",".join(transcode))
251 mux="ts{pid-video=%d,pid-audio=%d}" % (videoPid, audioPid)
252 input += "std{access=http,mux=%s,dst=/%s.ts} :sout-all :sout-keep" % (mux, streamName)
254 print "[VLC] playfile", input
256 xml = self.__xmlRequest("status", {"command": "in_play", "input": input})
257 error = xml.getElementsByTagName("error")
258 if error is not None and len(error) > 0:
259 self.lastError = getText(error[0].childNodes).strip()
260 if len(self.lastError) == 0:
261 self.lastError = None
263 print "[VLC] VlcControl error:", self.lastError
266 self.lastError = None
267 return "http://%s:%d/%s.ts" % (self.getHost(), self.getHttpPort(), streamName)
270 self.__xmlRequest("status", {"command": "pl_pause"})
273 self.__xmlRequest("status", {"command": "pl_stop"})
276 self.__xmlRequest("status", {"command": "pl_pause"})
278 def delete(self, id):
279 self.__xmlRequest("status", {"command": "pl_delete", "id": str(id)})
281 def deleteCurrentTree(self):
282 print "[VLC] delete current tree"
283 currentElement = self.getCurrentElement()
284 while currentElement is not None and currentElement.parentNode.getAttribute("ro") != "ro":
285 currentElement = currentElement.parentNode
286 id = int(currentElement.getAttribute("id"))
289 def seek(self, value):
290 """ Allowed values are of the form:
291 [+ or -][<int><H or h>:][<int><M or m or '>:][<int><nothing or S or s or ">]
293 (value between [ ] are optional, value between < > are mandatory)
295 1000 -> seek to the 1000th second
296 +1H:2M -> seek 1 hour and 2 minutes forward
297 -10% -> seek 10% back"""
298 self.__xmlRequest("status", {"command": "seek", "val": str(value)})
301 xml = self.__xmlRequest("status", None)
303 for e in xml.documentElement.childNodes:
304 if e.nodeType == e.ELEMENT_NODE:
305 if e.firstChild is None:
306 stats[e.nodeName.encode("latin_1", "replace")] = None
308 stats[e.nodeName.encode("latin_1", "replace")] = e.firstChild.nodeValue.encode("latin_1", "replace")
311 def loadPlaylist(self, playlist):
312 self.__xmlRequest("status", {"command": "in_play", "input": playlist})
313 self.__xmlRequest("status", {"command": "pl_stop"})
314 xml = self.__xmlRequest("playlist", None)
316 for n in xml.getElementsByTagName("node"):
317 if n.hasAttribute("name") is not None:
318 if n.getAttribute("name").encode("latin_1", "replace") == playlist:
320 id = n.getAttribute("id")
321 elif int(id) < int(n.getAttribute("id")):
322 id = n.getAttribute("id")