]> git.sesse.net Git - vlc/blob - share/lua/intf/modules/httprequests.lua
web intf: fix uri decoding when browsing.
[vlc] / share / lua / intf / modules / httprequests.lua
1 --[==========================================================================[
2  httprequests.lua: code for processing httprequests commands and output
3 --[==========================================================================[
4  Copyright (C) 2007 the VideoLAN team
5  $Id$
6
7  Authors: Antoine Cellerier <dionoea at videolan dot org>
8  Rob Jonson <rob at hobbyistsoftware.com>
9
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 --]==========================================================================]
24
25 module("httprequests",package.seeall)
26
27 local dkjson = require ("dkjson")
28
29
30
31 --Round the number to the specified precision
32 function round(what, precision)
33   if what then return math.floor(what*math.pow(10,precision)+0.5) / math.pow(10,precision) else return "" end
34 end
35
36 --split text where it matches the delimiter
37 function strsplit(text, delimiter)
38     local strfind = string.find
39     local strsub = string.sub
40     local tinsert = table.insert
41     local list = {}
42     local pos = 1
43     if strfind("", delimiter, 1) then -- this would result in endless loops
44         error("delimiter matches empty string!")
45     end
46     local i=1
47     while 1 do
48         i=i+1
49         local first, last = strfind(text, delimiter, pos)
50         if first then -- found?
51             tinsert(list,i, strsub(text, pos, first-1))
52             pos = last+1
53         else
54             tinsert(list,i, strsub(text, pos))
55         break
56         end
57     end
58     return list
59 end
60
61 function round(what, precision)
62 if what then return math.floor(what*math.pow(10,precision)+0.5) / math.pow(10,precision) else return "" end
63 end
64
65 --main function to process commands sent with the request
66
67 processcommands = function ()
68
69     local input = _GET['input']
70     local command = _GET['command']
71     local id = tonumber(_GET['id'] or -1)
72     local val = _GET['val']
73     local options = _GET['option']
74     local band = _GET['band']
75     if type(options) ~= "table" then -- Deal with the 0 or 1 option case
76       options = { options }
77     end
78
79     if command == "in_play" then
80       --[[
81       vlc.msg.err( "<options>" )
82       for a,b in ipairs(options) do
83         vlc.msg.err(b)
84       end
85       vlc.msg.err( "</options>" )
86       --]]
87       vlc.playlist.add({{path=vlc.strings.make_uri(input),options=options}})
88     elseif command == "addsubtitle" then
89       vlc.input.add_subtitle (vlc.strings.make_uri(val))
90     elseif command == "in_enqueue" then
91       vlc.playlist.enqueue({{path=vlc.strings.make_uri(input),options=options}})
92     elseif command == "pl_play" then
93       if id == -1 then
94         vlc.playlist.play()
95       else
96         vlc.playlist.goto(id)
97       end
98     elseif command == "pl_pause" then
99       if vlc.playlist.status() == "stopped" then
100         if id == -1 then
101           vlc.playlist.play()
102         else
103           vlc.playlist.goto(id)
104         end
105       else
106         vlc.playlist.pause()
107       end
108     elseif command == "pl_forcepause" then
109       if vlc.playlist.status() == "playing" then
110         vlc.playlist.pause()
111       end
112     elseif command == "pl_forceresume" then
113       if vlc.playlist.status() == "paused" then
114         vlc.playlist.pause()
115       end
116     elseif command == "pl_stop" then
117       vlc.playlist.stop()
118     elseif command == "pl_next" then
119       vlc.playlist.next()
120     elseif command == "pl_previous" then
121       vlc.playlist.prev()
122     elseif command == "pl_delete" then
123       vlc.playlist.delete(id)
124     elseif command == "pl_empty" then
125       vlc.playlist.clear()
126     elseif command == "pl_sort" then
127       vlc.playlist.sort( val, id > 0 )
128     elseif command == "pl_random" then
129       vlc.playlist.random()
130     elseif command == "pl_loop" then
131     --if loop is set true, then repeat needs to be set false
132       if vlc.playlist.loop() then
133         vlc.playlist.repeat_("off")
134       end
135     elseif command == "pl_repeat" then
136     --if repeat is set true, then loop needs to be set false
137       if vlc.playlist.repeat_() then
138         vlc.playlist.loop("off")
139       end
140     elseif command == "pl_sd" then
141       if vlc.sd.is_loaded(val) then
142         vlc.sd.remove(val)
143       else
144         vlc.sd.add(val)
145       end
146     elseif command == "fullscreen" then
147       vlc.video.fullscreen()
148     elseif command == "snapshot" then
149       common.snapshot()
150     elseif command == "volume" then
151       common.volume(val)
152     elseif command == "seek" then
153       common.seek(val)
154     elseif command == "key" then
155       common.hotkey("key-"..val)
156     elseif command == "audiodelay" then
157       if vlc.object.input() and val then
158        vlc.var.set(vlc.object.input(),"audio-delay",val)
159       end
160     elseif command == "rate" then
161       if vlc.object.input() and tonumber(val) >= 0 then
162        vlc.var.set(vlc.object.input(),"rate",val)
163       end
164     elseif command == "subdelay" then
165       if vlc.object.input() then
166        vlc.var.set(vlc.object.input(),"spu-delay",val)
167       end
168     elseif command == "aspectratio" then
169       if vlc.object.vout() then
170        vlc.var.set(vlc.object.vout(),"aspect-ratio",val)
171       end
172     elseif command == "preamp" then
173       vlc.equalizer.preampset(val)
174     elseif command == "equalizer" then
175       vlc.equalizer.equalizerset(band,val)
176     elseif command == "enableeq" then
177       if val == '0' then vlc.equalizer.enable(false) else vlc.equalizer.enable(true) end
178     elseif command == "setpreset" then
179       vlc.equalizer.setpreset(val)
180     end
181
182     local input = nil
183     local command = nil
184     local id = nil
185     local val = nil
186
187 end
188
189 --utilities for formatting output
190
191 function xmlString(s)
192   if (type(s)=="string") then
193       return vlc.strings.convert_xml_special_chars(s)
194   else
195       return tostring(s)
196   end
197 end
198
199 --dkjson outputs numbered tables as arrays
200 --so we don't need the array indicators
201 function removeArrayIndicators(dict)
202     local newDict=dict
203
204     for k,v in pairs(dict) do
205         if (type(v)=="table") then
206             local arrayEntry=v._array
207             if arrayEntry then
208                 v=arrayEntry
209             end
210
211             dict[k]=removeArrayIndicators(v)
212         end
213     end
214
215     return newDict
216 end
217
218 printTableAsJson = function (dict)
219     dict=removeArrayIndicators(dict)
220
221     local output=dkjson.encode (dict, { indent = true })
222     print(output)
223 end
224
225 local printXmlKeyValue = function (k,v,indent)
226     print("\n")
227     for i=1,indent do print(" ") end
228     if (k) then
229         print("<"..k..">")
230     end
231
232     if (type(v)=="table") then
233         printTableAsXml(v,indent+2)
234     else
235         print(xmlString(v))
236     end
237
238     if (k) then
239         print("</"..xmlString(k)..">")
240     end
241 end
242
243 printTableAsXml = function (dict,indent)
244     for k,v in pairs(dict) do
245         printXmlKeyValue(k,v,indent)
246     end
247 end
248
249 --[[
250 function logTable(t,pre)
251   local pre = pre or ""
252   for k,v in pairs(t) do
253     vlc.msg.err(pre..tostring(k).." : "..tostring(v))
254     if type(v) == "table" then
255       a(v,pre.."  ")
256     end
257   end
258 end
259 --]]
260
261 --main accessors
262
263 getplaylist = function ()
264     local p
265
266     if _GET["search"] then
267       if _GET["search"] ~= "" then
268         _G.search_key = _GET["search"]
269       else
270         _G.search_key = nil
271       end
272       local key = vlc.strings.decode_uri(_GET["search"])
273       p = vlc.playlist.search(key)
274     else
275       p = vlc.playlist.get()
276     end
277
278     --logTable(p) --Uncomment to debug
279
280     return p
281 end
282
283 parseplaylist = function (item)
284     if item.flags.disabled then return end
285
286     if (item.children) then
287         local result={}
288         local name = (item.name or "")
289
290         result["type"]="node"
291         result.id=tostring(item.id)
292         result.name=tostring(name)
293         result.ro=item.flags.ro and "ro" or "rw"
294
295         --store children in an array
296         --we use _array as a proxy for arrays
297         result.children={}
298         result.children._array={}
299
300         for _, child in ipairs(item.children) do
301             local nextChild=parseplaylist(child)
302             table.insert(result.children._array,nextChild)
303         end
304
305         return result
306     else
307         local result={}
308         local name, path = item.name or ""
309         local path = item.path or ""
310         local current_item = vlc.input.item()
311
312         -- Is the item the one currently played
313         if(current_item ~= nil) then
314             if(vlc.input.item().uri(current_item) == path) then
315                 result.current = "current"
316             end
317         end
318
319         result["type"]="leaf"
320         result.id=tostring(item.id)
321         result.uri=tostring(path)
322         result.name=name
323         result.ro=item.flags.ro and "ro" or "rw"
324         result.duration=math.floor(item.duration)
325
326         return result
327     end
328
329 end
330
331 playlisttable = function ()
332
333     local basePlaylist=getplaylist()
334
335     return parseplaylist(basePlaylist)
336 end
337
338 getbrowsetable = function ()
339
340     local dir = nil
341     local uri = _GET["uri"]
342     --uri takes precedence, but fall back to dir
343     if uri then
344         if uri == "file://~" then
345             dir = uri
346         else
347             dir = vlc.strings.make_path(uri)
348         end
349     else
350         dir = _GET["dir"]
351     end
352
353     --backwards compatibility with old format driveLetter:\\..
354     --this is forgiving with the slash type and number
355     if dir then
356         local position=string.find(dir, '%a:[\\/]*%.%.',0)
357         if position==1 then dir="" end
358     end
359
360     local result={}
361     --paths are returned as an array of elements
362     result.element={}
363     result.element._array={}
364
365     if dir then
366         if dir == "~" or dir == "file://~" then dir = vlc.misc.homedir() end
367         -- FIXME: hack for Win32 drive list
368         if dir~="" then
369             dir = common.realpath(dir.."/")
370         end
371
372         local d = vlc.net.opendir(dir)
373         table.sort(d)
374
375         for _,f in pairs(d) do
376             if f == ".." or not string.match(f,"^%.") then
377                 local df = common.realpath(dir..f)
378                 local s = vlc.net.stat(df)
379                 local path, name =  df, f
380                 local element={}
381
382                 for k,v in pairs(s) do
383                     element[k]=v
384                 end
385                 element["path"]=path
386                 element["name"]=name
387
388                 local uri=vlc.strings.make_uri(df)
389                 --windows paths are returned with / separators, but make_uri expects \ for windows and returns nil
390                 if not uri then
391                     --convert failed path to windows format and try again
392                     path=string.gsub(path,"/","\\")
393                     uri=vlc.strings.make_uri(df)
394                 end
395                 element["uri"]=uri
396
397                 table.insert(result.element._array,element)
398             end
399
400         end
401     end
402
403     return result;
404 end
405
406
407 getstatus = function (includecategories)
408
409
410 local input = vlc.object.input()
411 local item = vlc.input.item()
412 local playlist = vlc.object.playlist()
413 local vout = vlc.object.vout()
414 local aout = vlc.object.aout()
415
416     local s ={}
417
418     --update api version when new data/commands added
419     s.apiversion=1
420     s.version=vlc.misc.version()
421     s.volume=vlc.volume.get()
422
423     if input then
424         s.length=math.floor(vlc.var.get(input,"length"))
425         s.time=math.floor(vlc.var.get(input,"time"))
426         s.position=vlc.var.get(input,"position")
427         s.audiodelay=vlc.var.get(input,"audio-delay")
428         s.rate=vlc.var.get(input,"rate")
429         s.subtitledelay=vlc.var.get(input,"spu-delay")
430     else
431         s.length=0
432         s.time=0
433         s.position=0
434         s.audiodelay=0
435         s.rate=1
436         s.subtitledelay=0
437     end
438
439     if vout then
440         s.fullscreen=vlc.var.get(vout,"fullscreen")
441         s.aspectratio=vlc.var.get(vout,"aspect-ratio");
442         if s.aspectratio=="" then s.aspectratio = "default" end
443     else
444         s.fullscreen=0
445     end
446
447     if aout then
448         local filters=vlc.var.get(aout,"audio-filter")
449         local temp=strsplit(filters,":")
450         s.audiofilters={}
451         local id=0
452         for i,j in pairs(temp) do
453             s.audiofilters['filter_'..id]=j
454             id=id+1
455         end
456     end
457
458     s.videoeffects={}
459     s.videoeffects.hue=round(vlc.config.get("hue"),2)
460     s.videoeffects.brightness=round(vlc.config.get("brightness"),2)
461     s.videoeffects.contrast=round(vlc.config.get("contrast"),2)
462     s.videoeffects.saturation=round(vlc.config.get("saturation"),2)
463     s.videoeffects.gamma=round(vlc.config.get("gamma"),2)
464
465     s.state=vlc.playlist.status()
466     s.random=vlc.var.get(playlist,"random")
467     s.loop=vlc.var.get(playlist,"loop")
468     s["repeat"]=vlc.var.get(playlist,"repeat")
469
470         s.equalizer={}
471         s.equalizer.preamp=round(vlc.equalizer.preampget(),2)
472         s.equalizer.bands=vlc.equalizer.equalizerget()
473             if s.equalizer.bands ~= null then
474                 for k,i in pairs(s.equalizer.bands) do s.equalizer.bands[k]=round(i,2) end
475                 s.equalizer.presets=vlc.equalizer.presets()
476         end
477
478     if (includecategories and item) then
479         s.information={}
480         s.information.category={}
481         s.information.category.meta=item:metas()
482
483         local info = item:info()
484         for k, v in pairs(info) do
485             local streamTable={}
486             for k2, v2 in pairs(v) do
487                 local tag = string.gsub(k2," ","_")
488                 streamTable[tag]=v2
489             end
490
491             s.information.category[k]=streamTable
492         end
493
494         s.stats={}
495
496         local statsdata = item:stats()
497           for k,v in pairs(statsdata) do
498             local tag = string.gsub(k,"_","")
499         s.stats[tag]=v
500       end
501     end
502     return s
503 end
504