remove unused import
[enigma2-plugins.git] / vlcplayer / src / VlcServer.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 import re
14 import posixpath
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
21
22 seed()
23
24 def normpath(path):
25         if path is None:
26                 return None
27         path = path.replace("\\","/").replace("//", "/")
28         if path == "/..":
29                 return None
30         if len(path) > 0 and path[0] != '/':
31                 path = posixpath.normpath('/' + path)[1:]
32         else:
33                 path = posixpath.normpath(path)
34
35         if len(path) == 0 or path == "//":
36                 return "/"
37         elif path == ".":
38                 return None
39         return path
40         
41
42 class VlcServer:
43         def __init__(self, cfg):
44                 self.cfg = cfg
45
46         def getCfg(self):
47                 return self.cfg
48
49         def getName(self):
50                 return self.cfg.name.value
51
52         def name(self):
53                 return self.cfg.name
54
55         def getAddressType(self):
56                 return self.cfg.addressType.value
57
58         def addressType(self):
59                 return self.cfg.addressType
60
61         def getHost(self):
62                 return self.cfg.hostip.tostring(self.cfg.hostip.value)
63
64         def host(self):
65                 return self.cfg.hostip
66
67         def getHttpPort(self):
68                 return self.cfg.httpport.value
69
70         def httpPort(self):
71                 return self.cfg.httpport
72
73         def getBasedir(self):
74                 return self.cfg.basedir.value
75
76         def basedir(self):
77                 return self.cfg.basedir
78
79         def getVideoCodec(self):
80                 return self.cfg.videocodec.value
81
82         def videoCodec(self):
83                 return self.cfg.videocodec
84
85         def getVideoBitrate(self):
86                 return self.cfg.videobitrate.value
87
88         def videoBitrate(self):
89                 return self.cfg.videobitrate
90
91         def getAudioCodec(self):
92                 return self.cfg.audiocodec.value
93
94         def audioCodec(self):
95                 return self.cfg.audiocodec
96
97         def getAudioBitrate(self):
98                 return self.cfg.audiobitrate.value
99
100         def audioBitrate(self):
101                 return self.cfg.audiobitrate
102
103         def getSamplerate(self):
104                 return self.cfg.samplerate.value
105
106         def samplerate(self):
107                 return self.cfg.samplerate
108
109         def getAudioChannels(self):
110                 return self.cfg.audiochannels.value
111
112         def audioChannels(self):
113                 return self.cfg.audiochannels
114
115         def getVideoNorm(self):
116                 return self.cfg.videonorm.value
117
118         def videoNorm(self):
119                 return self.cfg.videonorm
120
121         def getOverscanCorrection(self):
122                 return self.cfg.overscancorrection.value
123
124         def overscanCorrection(self):
125                 return self.cfg.overscancorrection
126
127         def getSOverlay(self):
128                 return self.cfg.soverlay.value
129
130         def sOverlay(self):
131                 return self.cfg.soverlay
132
133         def getTranscodeVideo(self):
134                 return self.cfg.transcodeVideo.value
135
136         def transcodeVideo(self):
137                 return self.cfg.transcodeVideo
138
139         def getTranscodeAudio(self):
140                 return self.cfg.transcodeAudio.value
141
142         def transcodeAudio(self):
143                 return self.cfg.transcodeAudio
144
145         def dvdPath(self):
146                 return self.cfg.dvdPath
147
148         def getDvdPath(self):
149                 return self.cfg.dvdPath.value
150
151         def __xmlRequest(self, request, params):
152                 uri = "/requests/" + request + ".xml"
153                 if params is not None: uri = uri + "?" + urlencode(params)
154                 location = "%s:%d" % (self.getHost(), self.getHttpPort())
155                 resp = urlopen("http://" + location + uri)
156                 if resp is None:
157                         raise IOError, "No response from Server"
158                 xml = parse(resp)
159                 resp.close()
160                 return xml
161
162         def getFilesAndDirs(self, directory, regex):
163                 files = []
164                 directories = []
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"))
170                                 if path is not None:
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)
178
179         def getPlaylistEntries(self):
180                 xml = self.__xmlRequest("playlist", None)
181                 files = []
182                 for e in xml.getElementsByTagName("leaf"):
183                         if e.hasAttribute("uri") is not None:
184                                 name = e.getAttribute("name").encode("utf8")
185                                 if len(name) >= 50:
186                                         name = "..." + name[-50:]
187                                 path = e.getAttribute("uri").encode("utf8")
188                                 files.append([name, path])
189                 return files
190
191         def getCurrentElement(self):
192                 xml = self.__xmlRequest("playlist", None)
193                 for e in xml.getElementsByTagName("leaf"):
194                         if e.hasAttribute("current"):
195                                 return e
196                 return None
197
198         def play(self, session, media, name, currentList = None, player = None):
199                 if player is None:
200 # or not isinstance(player, VlcPlayer):
201                         player = VlcPlayer
202                 dlg = session.open(player, self, currentList)
203                 dlg.playfile(media, name)
204                 return dlg
205         
206         def playFile(self, filename, videoPid, audioPid):
207                 streamName = "dream" + str(randint(0, maxint))
208                 transcode = []
209
210                 doDirect = isDvdUrl(filename) or re.match("(?i).*\.(mpg|mpeg|ts)$", filename.lower())
211
212                 if not doDirect or self.getTranscodeVideo():
213                         videoNormList = self.getVideoNorm().split(",")
214 #                       ,height=%s
215                         transcode.append("vcodec=%s,vb=%d,venc=ffmpeg{strict-rc=1},width=%s,height=%s,canvas-width=%s,canvas-height=%s,canvas-aspect=%s,fps=%s" % (
216                                 self.getVideoCodec(),self.getVideoBitrate(),
217                                 str(int(float(videoNormList[0]) - float(videoNormList[0]) * float(self.getOverscanCorrection()) / 100)),
218                                 str(int(float(videoNormList[1]) - float(videoNormList[1]) * float(self.getOverscanCorrection()) / 100)),
219                                 videoNormList[0], videoNormList[1], videoNormList[2], videoNormList[3]
220                         ))
221                         if self.getSOverlay():
222                                 transcode.append("soverlay")
223                 if not doDirect or self.getTranscodeAudio():
224                         transcode.append("acodec=%s,ab=%d,channels=%d,samplerate=%s" % (
225                                 self.getAudioCodec(),
226                                 self.getAudioBitrate(),
227                                 self.getAudioChannels(),
228                                 self.getSamplerate()
229                         ))
230                 if re.match("[a-zA-Z]:", filename):
231                         # Fix for subtitles with VLC on Windows.
232                         filename = filename.replace("/", "\\")
233
234                 filename = filename.replace("\\", "\\\\").replace("'", "\\'")
235 #               input = filename + " :dvdread-caching=3000 :sub-track=1 :audio-track=1 :sout=#"
236                 input = filename + " :sout=#"
237
238                 if len(transcode) > 0:
239                         input += "transcode{%s}:" % (",".join(transcode))
240
241                 mux="ts{pid-video=%d,pid-audio=%d}" % (videoPid, audioPid)
242                 input += "std{access=http,mux=%s,dst=/%s.ts} :sout-all :sout-keep" % (mux, streamName)
243
244                 print "[VLC] playfile", input
245
246                 xml = self.__xmlRequest("status", {"command": "in_play", "input": input})
247                 error = xml.getElementsByTagName("error")
248                 if error is not None and len(error) > 0:
249                         self.lastError = getText(error[0].childNodes).strip()
250                         if len(self.lastError) == 0:
251                                 self.lastError = None
252                         else:
253                                 print "[VLC] VlcControl error:", self.lastError
254                         return None
255                 else:
256                         self.lastError = None
257                 return "http://%s:%d/%s.ts" % (self.getHost(), self.getHttpPort(), streamName)
258
259         def unpause(self):
260                 self.__xmlRequest("status", {"command": "pl_pause"})
261
262         def stop(self):
263                 self.__xmlRequest("status", {"command": "pl_stop"})
264
265         def pause(self):
266                 self.__xmlRequest("status", {"command": "pl_pause"})
267
268         def delete(self, id):
269                 self.__xmlRequest("status", {"command": "pl_delete", "id": str(id)})
270
271         def deleteCurrentTree(self):
272                 print "[VLC] delete current tree"
273                 currentElement = self.getCurrentElement()
274                 while currentElement is not None and currentElement.parentNode.getAttribute("ro") != "ro":
275                         currentElement = currentElement.parentNode
276                 id = int(currentElement.getAttribute("id"))
277                 self.delete(id)
278                 
279         def seek(self, value):
280                 """  Allowed values are of the form:
281   [+ or -][<int><H or h>:][<int><M or m or '>:][<int><nothing or S or s or ">]
282   or [+ or -]<int>%
283   (value between [ ] are optional, value between < > are mandatory)
284 examples:
285   1000 -> seek to the 1000th second
286   +1H:2M -> seek 1 hour and 2 minutes forward
287   -10% -> seek 10% back"""
288                 self.__xmlRequest("status", {"command": "seek", "val": str(value)})
289
290         def status(self):
291                 xml = self.__xmlRequest("status", None)
292                 stats = {}
293                 for e in xml.documentElement.childNodes:
294                         if e.nodeType == e.ELEMENT_NODE:
295                                 if e.firstChild is None:
296                                         stats[e.nodeName.encode("latin_1", "replace")] = None
297                                 else:
298                                         stats[e.nodeName.encode("latin_1", "replace")] = e.firstChild.nodeValue.encode("latin_1", "replace")
299                 return stats
300
301         def loadPlaylist(self, playlist):
302                 self.__xmlRequest("status", {"command": "in_play", "input": playlist})
303                 self.__xmlRequest("status", {"command": "pl_stop"})
304                 xml = self.__xmlRequest("playlist", None)
305                 id = None
306                 for n in xml.getElementsByTagName("node"):
307                         if n.hasAttribute("name") is not None:
308                                 if n.getAttribute("name").encode("utf8", "replace") == playlist:
309                                         if id is None:
310                                                 id = n.getAttribute("id")
311                                         elif int(id) < int(n.getAttribute("id")):
312                                                 id = n.getAttribute("id")
313                 return id