1 --[==========================================================================[
2 httprequests.lua: code for processing httprequests commands and output
3 --[==========================================================================[
4 Copyright (C) 2007 the VideoLAN team
7 Authors: Antoine Cellerier <dionoea at videolan dot org>
8 Rob Jonson <rob at hobbyistsoftware.com>
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.
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.
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 --]==========================================================================]
25 module("httprequests",package.seeall)
27 local dkjson = require ("dkjson")
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
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
43 if strfind("", delimiter, 1) then -- this would result in endless loops
44 error("delimiter matches empty string!")
49 local first, last = strfind(text, delimiter, pos)
50 if first then -- found?
51 tinsert(list,i, strsub(text, pos, first-1))
54 tinsert(list,i, strsub(text, pos))
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
65 --main function to process commands sent with the request
67 processcommands = function ()
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
79 if command == "in_play" then
81 vlc.msg.err( "<options>" )
82 for a,b in ipairs(options) do
85 vlc.msg.err( "</options>" )
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
96 vlc.playlist.gotoitem(id)
98 elseif command == "pl_pause" then
99 if vlc.playlist.status() == "stopped" then
103 vlc.playlist.gotoitem(id)
108 elseif command == "pl_forcepause" then
109 if vlc.playlist.status() == "playing" then
112 elseif command == "pl_forceresume" then
113 if vlc.playlist.status() == "paused" then
116 elseif command == "pl_stop" then
118 elseif command == "pl_next" then
120 elseif command == "pl_previous" then
122 elseif command == "pl_delete" then
123 vlc.playlist.delete(id)
124 elseif command == "pl_empty" then
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")
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")
140 elseif command == "pl_sd" then
141 if vlc.sd.is_loaded(val) then
146 elseif command == "fullscreen" then
147 vlc.video.fullscreen()
148 elseif command == "snapshot" then
150 elseif command == "volume" then
152 elseif command == "seek" then
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)
160 elseif command == "rate" then
161 if vlc.object.input() and tonumber(val) >= 0 then
162 vlc.var.set(vlc.object.input(),"rate",val)
164 elseif command == "subdelay" then
165 if vlc.object.input() then
166 vlc.var.set(vlc.object.input(),"spu-delay",val)
168 elseif command == "aspectratio" then
169 if vlc.object.vout() then
170 vlc.var.set(vlc.object.vout(),"aspect-ratio",val)
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 elseif command == "title" then
181 vlc.var.set(vlc.object.input(), "title", val)
182 elseif command == "chapter" then
183 vlc.var.set(vlc.object.input(), "chapter", val)
184 elseif command == "audio_track" then
185 vlc.var.set(vlc.object.input(), "audio-es", val)
186 elseif command == "video_track" then
187 vlc.var.set(vlc.object.input(), "video-es", val)
188 elseif command == "subtitle_track" then
189 vlc.var.set(vlc.object.input(), "spu-es", val)
199 --utilities for formatting output
201 function xmlString(s)
202 if (type(s)=="string") then
203 return vlc.strings.convert_xml_special_chars(s)
209 --dkjson outputs numbered tables as arrays
210 --so we don't need the array indicators
211 function removeArrayIndicators(dict)
214 for k,v in pairs(dict) do
215 if (type(v)=="table") then
216 local arrayEntry=v._array
221 dict[k]=removeArrayIndicators(v)
228 printTableAsJson = function (dict)
229 dict=removeArrayIndicators(dict)
231 local output=dkjson.encode (dict, { indent = true })
235 local printXmlKeyValue = function (k,v,indent)
237 for i=1,indent do print(" ") end
242 if (type(v)=="table") then
243 printTableAsXml(v,indent+2)
250 space_loc=string.find(xs," ")
251 if space_loc == nil then
254 xs=string.sub(xs,1,space_loc)
260 printTableAsXml = function (dict,indent)
261 for k,v in pairs(dict) do
262 printXmlKeyValue(k,v,indent)
267 function logTable(t,pre)
268 local pre = pre or ""
269 for k,v in pairs(t) do
270 vlc.msg.err(pre..tostring(k).." : "..tostring(v))
271 if type(v) == "table" then
280 getplaylist = function ()
283 if _GET["search"] then
284 if _GET["search"] ~= "" then
285 _G.search_key = _GET["search"]
289 local key = vlc.strings.decode_uri(_GET["search"])
290 p = vlc.playlist.search(key)
292 p = vlc.playlist.get()
295 --logTable(p) --Uncomment to debug
300 parseplaylist = function (item)
301 if item.flags.disabled then return end
303 if (item.children) then
305 local name = (item.name or "")
307 result["type"]="node"
308 result.id=tostring(item.id)
309 result.name=tostring(name)
310 result.ro=item.flags.ro and "ro" or "rw"
312 --store children in an array
313 --we use _array as a proxy for arrays
315 result.children._array={}
317 for _, child in ipairs(item.children) do
318 local nextChild=parseplaylist(child)
319 table.insert(result.children._array,nextChild)
325 local name, path = item.name or ""
326 local path = item.path or ""
327 local current_item = vlc.input.item()
329 -- Is the item the one currently played
330 if(current_item ~= nil) then
331 if(vlc.input.item().uri(current_item) == path) then
332 result.current = "current"
336 result["type"]="leaf"
337 result.id=tostring(item.id)
338 result.uri=tostring(path)
340 result.ro=item.flags.ro and "ro" or "rw"
341 result.duration=math.floor(item.duration)
348 playlisttable = function ()
350 local basePlaylist=getplaylist()
352 return parseplaylist(basePlaylist)
355 getbrowsetable = function ()
358 local uri = _GET["uri"]
359 --uri takes precedence, but fall back to dir
361 if uri == "file://~" then
364 dir = vlc.strings.make_path(uri)
370 --backwards compatibility with old format driveLetter:\\..
371 --this is forgiving with the slash type and number
373 local position=string.find(dir, '%a:[\\/]*%.%.',0)
374 if position==1 then dir="" end
378 --paths are returned as an array of elements
380 result.element._array={}
383 if dir == "~" or dir == "file://~" then dir = vlc.config.homedir() end
384 -- FIXME: hack for Win32 drive list
386 dir = common.realpath(dir.."/")
389 local d = vlc.net.opendir(dir)
392 for _,f in pairs(d) do
393 if f == ".." or not string.match(f,"^%.") then
394 local df = common.realpath(dir..f)
395 local s = vlc.net.stat(df)
396 local path, name = df, f
400 for k,v in pairs(s) do
404 element["type"]="unknown"
409 local uri=vlc.strings.make_uri(df)
410 --windows paths are returned with / separators, but make_uri expects \ for windows and returns nil
412 --convert failed path to windows format and try again
413 path=string.gsub(path,"/","\\")
414 uri=vlc.strings.make_uri(df)
418 table.insert(result.element._array,element)
428 getstatus = function (includecategories)
431 local input = vlc.object.input()
432 local item = vlc.input.item()
433 local playlist = vlc.object.playlist()
434 local vout = vlc.object.vout()
435 local aout = vlc.object.aout()
439 --update api version when new data/commands added
441 s.version=vlc.misc.version()
442 s.volume=vlc.volume.get()
445 s.length=math.floor(vlc.var.get(input,"length"))
446 s.time=math.floor(vlc.var.get(input,"time"))
447 s.position=vlc.var.get(input,"position")
448 s.audiodelay=vlc.var.get(input,"audio-delay")
449 s.rate=vlc.var.get(input,"rate")
450 s.subtitledelay=vlc.var.get(input,"spu-delay")
461 s.fullscreen=vlc.var.get(vout,"fullscreen")
462 s.aspectratio=vlc.var.get(vout,"aspect-ratio");
463 if s.aspectratio=="" then s.aspectratio = "default" end
469 local filters=vlc.var.get(aout,"audio-filter")
470 local temp=strsplit(filters,":")
473 for i,j in pairs(temp) do
474 s.audiofilters['filter_'..id]=j
480 s.videoeffects.hue=round(vlc.config.get("hue"),2)
481 s.videoeffects.brightness=round(vlc.config.get("brightness"),2)
482 s.videoeffects.contrast=round(vlc.config.get("contrast"),2)
483 s.videoeffects.saturation=round(vlc.config.get("saturation"),2)
484 s.videoeffects.gamma=round(vlc.config.get("gamma"),2)
486 s.state=vlc.playlist.status()
487 s.random=vlc.var.get(playlist,"random")
488 s.loop=vlc.var.get(playlist,"loop")
489 s["repeat"]=vlc.var.get(playlist,"repeat")
492 s.equalizer.preamp=round(vlc.equalizer.preampget(),2)
493 s.equalizer.bands=vlc.equalizer.equalizerget()
494 if s.equalizer.bands ~= null then
495 for k,i in pairs(s.equalizer.bands) do s.equalizer.bands[k]=round(i,2) end
496 s.equalizer.presets=vlc.equalizer.presets()
499 if (includecategories and item) then
501 s.information.category={}
502 s.information.category.meta=item:metas()
504 local info = item:info()
505 for k, v in pairs(info) do
507 for k2, v2 in pairs(v) do
508 local tag = string.gsub(k2," ","_")
512 s.information.category[k]=streamTable
517 local statsdata = item:stats()
518 for k,v in pairs(statsdata) do
519 local tag = string.gsub(k,"_","")
523 s.information.chapters=vlc.var.get_list(input, "chapter")
524 s.information.titles=vlc.var.get_list(input, "title")