Revert "lua/http: add pl_sd_(add|remove) HTTP requests"
[vlc.git] / 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 common = require ("common")
28 local dkjson = require ("dkjson")
29
30
31
32 --Round the number to the specified precision
33 function round(what, precision)
34     if type(what) == "string" then
35         what = common.us_tonumber(what)
36     end
37     if type(what) == "number" then
38         return math.floor(what*math.pow(10,precision)+0.5) / math.pow(10,precision)
39     end
40     return nil
41 end
42
43 --split text where it matches the delimiter
44 function strsplit(text, delimiter)
45     local strfind = string.find
46     local strsub = string.sub
47     local tinsert = table.insert
48     local list = {}
49     local pos = 1
50     if strfind("", delimiter, 1) then -- this would result in endless loops
51         error("delimiter matches empty string!")
52     end
53     local i=1
54     while 1 do
55         local first, last = strfind(text, delimiter, pos)
56         if first then -- found?
57             tinsert(list,i, strsub(text, pos, first-1))
58             pos = last+1
59         else
60             tinsert(list,i, strsub(text, pos))
61             break
62         end
63         i = i+1
64     end
65     return list
66 end
67
68 --main function to process commands sent with the request
69
70 processcommands = function ()
71
72     local input = _GET['input']
73     local command = _GET['command']
74     local id = tonumber(_GET['id'] or -1)
75     local val = _GET['val']
76     local options = _GET['option']
77     local band = tonumber(_GET['band'])
78     local name = _GET['name']
79     local duration = tonumber(_GET['duration'])
80     if type(options) ~= "table" then -- Deal with the 0 or 1 option case
81         options = { options }
82     end
83
84     if command == "in_play" then
85         --[[
86         vlc.msg.err( "<options>" )
87         for a,b in ipairs(options) do
88         vlc.msg.err(b)
89         end
90         vlc.msg.err( "</options>" )
91         --]]
92         vlc.playlist.add({{path=vlc.strings.make_uri(input),options=options,name=name,duration=duration}})
93     elseif command == "addsubtitle" then
94         vlc.player.add_subtitle(val)
95     elseif command == "in_enqueue" then
96         vlc.playlist.enqueue({{path=vlc.strings.make_uri(input),options=options,name=name,duration=duration}})
97     elseif command == "pl_play" then
98         if id == -1 then
99             vlc.playlist.play()
100         else
101             vlc.playlist.gotoitem(id)
102         end
103     elseif command == "pl_pause" then
104         if vlc.playlist.status() == "stopped" then
105             if id == -1 then
106                 vlc.playlist.play()
107             else
108                 vlc.playlist.gotoitem(id)
109             end
110         else
111             vlc.playlist.pause()
112         end
113     elseif command == "pl_forcepause" then
114         if vlc.playlist.status() == "playing" then
115             vlc.playlist.pause()
116         end
117     elseif command == "pl_forceresume" then
118         if vlc.playlist.status() == "paused" then
119             vlc.playlist.pause()
120         end
121     elseif command == "pl_stop" then
122         vlc.playlist.stop()
123     elseif command == "pl_next" then
124         vlc.playlist.next()
125     elseif command == "pl_previous" then
126         vlc.playlist.prev()
127     elseif command == "pl_delete" then
128         vlc.playlist.delete(id)
129     elseif command == "pl_empty" then
130         vlc.playlist.clear()
131     elseif command == "pl_sort" then
132         vlc.playlist.sort( val, id > 0 )
133     elseif command == "pl_random" then
134         vlc.playlist.random()
135     elseif command == "pl_loop" then
136         vlc.playlist.loop()
137     elseif command == "pl_repeat" then
138         vlc.playlist.repeat_()
139     elseif command == "fullscreen" then
140         if vlc.object.vout() then
141             vlc.video.fullscreen()
142         end
143     elseif command == "snapshot" then
144         common.snapshot()
145     elseif command == "volume" then
146         common.volume(val)
147     elseif command == "seek" then
148         common.seek(val)
149     elseif command == "key" then
150         common.hotkey("key-"..val)
151     elseif command == "audiodelay" then
152         val = common.us_tonumber(val)
153         vlc.player.set_audio_delay(val)
154     elseif command == "rate" then
155         val = common.us_tonumber(val)
156         if val >= 0 then
157             vlc.player.set_rate(val)
158         end
159     elseif command == "subdelay" then
160         val = common.us_tonumber(val)
161         vlc.player.set_subtitle_delay(val)
162     elseif command == "aspectratio" then
163         if vlc.object.vout() then
164             vlc.var.set(vlc.object.vout(),"aspect-ratio",val)
165         end
166     elseif command == "preamp" then
167         val = common.us_tonumber(val)
168         vlc.equalizer.preampset(val)
169     elseif command == "equalizer" then
170         val = common.us_tonumber(val)
171         vlc.equalizer.equalizerset(band,val)
172     elseif command == "enableeq" then
173         if val == '0' then vlc.equalizer.enable(false) else vlc.equalizer.enable(true) end
174     elseif command == "setpreset" then
175         vlc.equalizer.setpreset(val)
176     elseif command == "title" then
177         vlc.player.title_goto(val)
178     elseif command == "chapter" then
179         vlc.player.chapter_goto(val)
180     elseif command == "audio_track" then
181         vlc.player.toggle_audio_track(val)
182     elseif command == "video_track" then
183         vlc.player.toggle_video_track(val)
184     elseif command == "subtitle_track" then
185         vlc.player.toggle_spu_track(val)
186     elseif command == "set_renderer" then
187         local rd = get_renderer_discovery()
188         if not rd then
189             return
190         end
191         rd:select(id)
192     elseif command == "unset_renderer" then
193         rd:select(-1)
194     end
195
196     local input = nil
197     local command = nil
198     local id = nil
199     local val = nil
200
201 end
202
203 --utilities for formatting output
204
205 function xmlString(s)
206     if (type(s)=="string") then
207         return vlc.strings.convert_xml_special_chars(s)
208     elseif (type(s)=="number") then
209         return common.us_tostring(s)
210     else
211         return tostring(s)
212     end
213 end
214
215 --dkjson outputs numbered tables as arrays
216 --so we don't need the array indicators
217 function removeArrayIndicators(dict)
218     local newDict=dict
219
220     for k,v in pairs(dict) do
221         if (type(v)=="table") then
222             local arrayEntry=v._array
223             if arrayEntry then
224                 v=arrayEntry
225             end
226
227             dict[k]=removeArrayIndicators(v)
228         end
229     end
230
231     return newDict
232 end
233
234 printTableAsJson = function (dict)
235     dict=removeArrayIndicators(dict)
236
237     local output=dkjson.encode (dict, { indent = true })
238     print(output)
239 end
240
241 local printXmlKeyValue = function (k,v,indent)
242     print("\n")
243     for i=1,indent do print(" ") end
244     if (k) then
245         --XML element naming rules: this is a bit more conservative
246         --than it strictly needs to be
247         if not string.match(k, "^[a-zA-Z_][a-zA-Z0-9_%-%.]*$")
248             or string.match(k, "^[xX][mM][lL]") then
249             print('<element name="'..xmlString(k)..'">')
250             k = "element"
251         else
252             print("<"..k..">")
253         end
254     end
255
256     if (type(v)=="table") then
257         printTableAsXml(v,indent+2)
258     else
259         print(xmlString(v))
260     end
261
262     if (k) then
263         print("</"..k..">")
264     end
265 end
266
267 printTableAsXml = function (dict,indent)
268     for k,v in pairs(dict) do
269         printXmlKeyValue(k,v,indent)
270     end
271 end
272
273 --[[
274 function logTable(t,pre)
275 local pre = pre or ""
276 for k,v in pairs(t) do
277 vlc.msg.err(pre..tostring(k).." : "..tostring(v))
278 if type(v) == "table" then
279 a(v,pre.."  ")
280 end
281 end
282 end
283 --]]
284
285 --main accessors
286
287 getplaylist = function ()
288     local p
289     if _GET["search"] then
290         if _GET["search"] ~= "" then
291             _G.search_key = _GET["search"]
292         else
293             _G.search_key = nil
294         end
295         local key = vlc.strings.decode_uri(_GET["search"])
296         p = vlc.playlist.search(key)
297     else
298         p = vlc.playlist.list()
299     end
300
301     --logTable(p) --Uncomment to debug
302
303     return p
304 end
305
306 parseplaylist = function (list)
307     local playlist = {}
308     local current_item_id = vlc.playlist.current()
309     for i, item in ipairs(list) do
310         local result={}
311
312         local name, path = item.name or ""
313         local path = item.path or ""
314
315         -- Is the item the one currently played
316         if(current_item_id ~= nil) then
317             if(current_item_id == item.id) then
318                 result.current = "current"
319             end
320         end
321         result["type"]="leaf"
322         result.id=tostring(item.id)
323         result.uri=tostring(path)
324         result.name=name
325         result.duration=math.floor(item.duration)
326         playlist[i] = result
327     end
328     return playlist
329
330 end
331
332 playlisttable = function ()
333
334     local basePlaylist=getplaylist()
335
336     return parseplaylist(basePlaylist)
337 end
338
339 getbrowsetable = function ()
340
341     --paths are returned as an array of elements
342     local result = { element = { _array = {} } }
343
344     local dir
345     --uri takes precedence, but fall back to dir
346     if _GET["uri"] then
347         if _GET["uri"] == "file://~" then
348             dir = "~"
349         else
350             local uri = string.gsub(_GET["uri"], "[?#].*$", "")
351             if not string.match(uri, "/$") then
352                 uri = uri.."/"
353             end
354             dir = vlc.strings.make_path(common.realpath(uri))
355         end
356     elseif _GET["dir"] then
357         dir = _GET["dir"]
358
359         -- "" dir means listing all drive letters e.g. "A:\", "C:\"...
360         --however the opendir() API won't resolve "X:\.." to that behavior,
361         --so we offer this resolution as "backwards compatibility"
362         if string.match(dir, '^[a-zA-Z]:[\\/]*%.%.$') or
363            string.match(dir, '^[a-zA-Z]:[\\/]*%.%.[\\/]') then
364             dir = ""
365         end
366
367         if dir ~= "" and dir ~= "~" then
368             dir = dir.."/" --luckily Windows accepts '/' as '\'
369         end
370     end
371     if not dir then
372         return result
373     end
374
375     if dir == "~" then
376         dir = vlc.config.homedir().."/"
377     end
378
379     local d = vlc.net.opendir(dir)
380     table.sort(d)
381
382     --FIXME: this is the wrong place to do this, but this still offers
383     --some useful mitigation: see #25021
384     if #d == 0 and dir ~= "" then
385         table.insert(d, "..")
386     end
387
388     for _,f in pairs(d) do
389         if f == ".." or not string.match(f,"^%.") then
390             local path = dir..f
391             local element={}
392
393             local s = vlc.net.stat(path)
394             if (s) then
395                 for k,v in pairs(s) do
396                     element[k]=v
397                 end
398             else
399                 element["type"]="unknown"
400             end
401             element["path"]=path
402             element["name"]=f
403
404             local uri=vlc.strings.make_uri(path)
405             if uri then
406                 element["uri"]=common.realpath(uri)
407             end
408
409             table.insert(result.element._array,element)
410         end
411     end
412
413     return result;
414 end
415
416
417 getstatus = function (includecategories)
418
419
420     local item = vlc.player.item()
421     local playlist = vlc.object.playlist()
422     local vout = vlc.object.vout()
423     local aout = vlc.object.aout()
424
425     local s ={}
426
427     --update api version when new data/commands added
428     s.apiversion=4
429     s.version=vlc.misc.version()
430     s.volume=vlc.volume.get()
431
432     s.time = vlc.player.get_time() / 1000000
433     s.position = vlc.player.get_position()
434     s.currentplid = vlc.playlist.current()
435     s.audiodelay = vlc.player.get_audio_delay()
436     s.rate = vlc.player.get_rate()
437     s.subtitledelay = vlc.player.get_subtitle_delay()
438
439     if item then
440         s.length=math.floor(item:duration())
441     else
442         s.length=0
443     end
444
445     if vout then
446         s.fullscreen=vlc.var.get(vout,"fullscreen")
447         s.aspectratio=vlc.var.get(vout,"aspect-ratio");
448         if s.aspectratio=="" then s.aspectratio = "default" end
449     else
450         s.fullscreen=0
451     end
452
453     if aout then
454         local filters=vlc.var.get(aout,"audio-filter")
455         local temp=strsplit(filters,":")
456         s.audiofilters={}
457         local id=0
458         for i,j in pairs(temp) do
459             s.audiofilters['filter_'..id]=j
460             id=id+1
461         end
462     end
463
464     s.videoeffects={}
465     s.videoeffects.hue=round(vlc.config.get("hue"),2)
466     s.videoeffects.brightness=round(vlc.config.get("brightness"),2)
467     s.videoeffects.contrast=round(vlc.config.get("contrast"),2)
468     s.videoeffects.saturation=round(vlc.config.get("saturation"),2)
469     s.videoeffects.gamma=round(vlc.config.get("gamma"),2)
470
471     s.state=vlc.playlist.status()
472     s.random = vlc.playlist.get_random()
473     s.loop = vlc.playlist.get_loop()
474     s["repeat"] = vlc.playlist.get_repeat()
475
476     s.equalizer={}
477     s.equalizer.preamp=round(vlc.equalizer.preampget(),2)
478     s.equalizer.bands=vlc.equalizer.equalizerget()
479     if s.equalizer.bands ~= null then
480         for k,i in pairs(s.equalizer.bands) do s.equalizer.bands[k]=round(i,2) end
481         s.equalizer.presets=vlc.equalizer.presets()
482     end
483
484     if (includecategories and item) then
485         s.information={}
486         s.information.category={}
487         s.information.category.meta=item:metas()
488
489         local info = item:info()
490         for k, v in pairs(info) do
491             local streamTable={}
492             for k2, v2 in pairs(v) do
493                 local tag = string.gsub(k2," ","_")
494                 streamTable[tag]=v2
495             end
496
497             s.information.category[k]=streamTable
498         end
499
500         s.stats={}
501
502         local statsdata = item:stats()
503         for k,v in pairs(statsdata) do
504             local tag = string.gsub(k,"_","")
505             s.stats[tag]=v
506         end
507
508         s.information.chapter = vlc.player.get_chapter_index()
509         s.information.title = vlc.player.get_title_index()
510
511         s.information.chapters_count = vlc.player.get_chapters_count()
512         s.information.titles_count = vlc.player.get_titles_count()
513
514     end
515     return s
516 end
517
518 get_renderers = function()
519     local rd = get_renderer_discovery()
520     if not rd then
521         return {}
522     end
523     return rd:list()
524 end