httprequests.lua 15.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
--[==========================================================================[
 httprequests.lua: code for processing httprequests commands and output
--[==========================================================================[
 Copyright (C) 2007 the VideoLAN team
 $Id$

 Authors: Antoine Cellerier <dionoea at videolan dot org>
 Rob Jonson <rob at hobbyistsoftware.com>

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
--]==========================================================================]

module("httprequests",package.seeall)

27
local common = require ("common")
Rob Jonson's avatar
Rob Jonson committed
28
local dkjson = require ("dkjson")
29 30 31



32
--Round the number to the specified precision
Akash Mehrotra's avatar
Akash Mehrotra committed
33
function round(what, precision)
34 35 36 37 38 39 40
    if type(what) == "string" then
        what = common.us_tonumber(what)
    end
    if type(what) == "number" then
        return math.floor(what*math.pow(10,precision)+0.5) / math.pow(10,precision)
    end
    return nil
Akash Mehrotra's avatar
Akash Mehrotra committed
41 42
end

43
--split text where it matches the delimiter
44
function strsplit(text, delimiter)
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    local strfind = string.find
    local strsub = string.sub
    local tinsert = table.insert
    local list = {}
    local pos = 1
    if strfind("", delimiter, 1) then -- this would result in endless loops
        error("delimiter matches empty string!")
    end
    local i=1
    while 1 do
        local first, last = strfind(text, delimiter, pos)
        if first then -- found?
            tinsert(list,i, strsub(text, pos, first-1))
            pos = last+1
        else
            tinsert(list,i, strsub(text, pos))
61
            break
62
        end
63
        i = i+1
64 65
    end
    return list
66 67
end

68 69 70
--main function to process commands sent with the request

processcommands = function ()
71

72 73 74 75 76
    local input = _GET['input']
    local command = _GET['command']
    local id = tonumber(_GET['id'] or -1)
    local val = _GET['val']
    local options = _GET['option']
77
    local band = tonumber(_GET['band'])
78 79
    local name = _GET['name']
    local duration = tonumber(_GET['duration'])
80
    if type(options) ~= "table" then -- Deal with the 0 or 1 option case
81
        options = { options }
82 83 84
    end

    if command == "in_play" then
85 86 87
        --[[
        vlc.msg.err( "<options>" )
        for a,b in ipairs(options) do
88
        vlc.msg.err(b)
89 90 91
        end
        vlc.msg.err( "</options>" )
        --]]
92
        vlc.playlist.add({{path=vlc.strings.make_uri(input),options=options,name=name,duration=duration}})
93
    elseif command == "addsubtitle" then
94
        vlc.input.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 98
    elseif command == "pl_play" then
        if id == -1 then
99 100 101 102 103 104 105 106 107 108 109
            vlc.playlist.play()
        else
            vlc.playlist.gotoitem(id)
        end
    elseif command == "pl_pause" then
        if vlc.playlist.status() == "stopped" then
            if id == -1 then
                vlc.playlist.play()
            else
                vlc.playlist.gotoitem(id)
            end
110
        else
111
            vlc.playlist.pause()
112 113
        end
    elseif command == "pl_forcepause" then
114 115 116
        if vlc.playlist.status() == "playing" then
            vlc.playlist.pause()
        end
117
    elseif command == "pl_forceresume" then
118 119 120
        if vlc.playlist.status() == "paused" then
            vlc.playlist.pause()
        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 137 138 139
        --if loop is set true, then repeat needs to be set false
        if vlc.playlist.loop() then
            vlc.playlist.repeat_("off")
        end
140
    elseif command == "pl_repeat" then
141 142 143 144
        --if repeat is set true, then loop needs to be set false
        if vlc.playlist.repeat_() then
            vlc.playlist.loop("off")
        end
145
    elseif command == "pl_sd" then
146 147 148 149 150
        if vlc.sd.is_loaded(val) then
            vlc.sd.remove(val)
        else
            vlc.sd.add(val)
        end
151
    elseif command == "fullscreen" then
152 153 154
        if vlc.object.vout() then
            vlc.video.fullscreen()
        end
155
    elseif command == "snapshot" then
156
        common.snapshot()
157
    elseif command == "volume" then
158
        common.volume(val)
159
    elseif command == "seek" then
160
        common.seek(val)
161
    elseif command == "key" then
162
        common.hotkey("key-"..val)
163
    elseif command == "audiodelay" then
164 165
        if vlc.object.input() and val then
            val = common.us_tonumber(val)
166
            vlc.var.set(vlc.object.input(),"audio-delay",val * 1000000)
167
        end
168
    elseif command == "rate" then
169 170 171 172
        val = common.us_tonumber(val)
        if vlc.object.input() and val >= 0 then
            vlc.var.set(vlc.object.input(),"rate",val)
        end
173
    elseif command == "subdelay" then
174 175
        if vlc.object.input() then
            val = common.us_tonumber(val)
176
            vlc.var.set(vlc.object.input(),"spu-delay",val * 1000000)
177
        end
178
    elseif command == "aspectratio" then
179 180 181
        if vlc.object.vout() then
            vlc.var.set(vlc.object.vout(),"aspect-ratio",val)
        end
182
    elseif command == "preamp" then
183 184
        val = common.us_tonumber(val)
        vlc.equalizer.preampset(val)
185
    elseif command == "equalizer" then
186 187
        val = common.us_tonumber(val)
        vlc.equalizer.equalizerset(band,val)
188
    elseif command == "enableeq" then
189
        if val == '0' then vlc.equalizer.enable(false) else vlc.equalizer.enable(true) end
190
    elseif command == "setpreset" then
191
        vlc.equalizer.setpreset(val)
192
    elseif command == "title" then
193 194 195 196 197 198 199 200 201
        vlc.var.set(vlc.object.input(), "title", val)
    elseif command == "chapter" then
        vlc.var.set(vlc.object.input(), "chapter", val)
    elseif command == "audio_track" then
        vlc.var.set(vlc.object.input(), "audio-es", val)
    elseif command == "video_track" then
        vlc.var.set(vlc.object.input(), "video-es", val)
    elseif command == "subtitle_track" then
        vlc.var.set(vlc.object.input(), "spu-es", val)
202 203 204 205 206 207
    end

    local input = nil
    local command = nil
    local id = nil
    local val = nil
208 209 210 211 212

end

--utilities for formatting output

213
function xmlString(s)
214 215 216 217 218 219 220
    if (type(s)=="string") then
        return vlc.strings.convert_xml_special_chars(s)
    elseif (type(s)=="number") then
        return common.us_tostring(s)
    else
        return tostring(s)
    end
221 222
end

Rob Jonson's avatar
Rob Jonson committed
223 224 225
--dkjson outputs numbered tables as arrays
--so we don't need the array indicators
function removeArrayIndicators(dict)
226
    local newDict=dict
227

228 229 230 231 232 233
    for k,v in pairs(dict) do
        if (type(v)=="table") then
            local arrayEntry=v._array
            if arrayEntry then
                v=arrayEntry
            end
Rob Jonson's avatar
Rob Jonson committed
234

235 236 237
            dict[k]=removeArrayIndicators(v)
        end
    end
Rob Jonson's avatar
Rob Jonson committed
238

239
    return newDict
Rob Jonson's avatar
Rob Jonson committed
240
end
241

Rob Jonson's avatar
Rob Jonson committed
242
printTableAsJson = function (dict)
243
    dict=removeArrayIndicators(dict)
Rob Jonson's avatar
Rob Jonson committed
244

245 246
    local output=dkjson.encode (dict, { indent = true })
    print(output)
247 248 249
end

local printXmlKeyValue = function (k,v,indent)
250 251 252 253 254 255 256 257 258 259
    print("\n")
    for i=1,indent do print(" ") end
    if (k) then
        print("<"..k..">")
    end

    if (type(v)=="table") then
        printTableAsXml(v,indent+2)
    else
        print(xmlString(v))
260
    end
261

262
    if (k) then
Akash Mehrotra's avatar
Akash Mehrotra committed
263 264 265 266 267 268 269 270
        xs=xmlString(k)
        space_loc=string.find(xs," ")
        if space_loc == nil then
            print("</"..xs..">")
        else
            xs=string.sub(xs,1,space_loc)
            print("</"..xs..">")
        end
271
    end
272 273 274
end

printTableAsXml = function (dict,indent)
275
    for k,v in pairs(dict) do
276 277 278 279 280 281
        printXmlKeyValue(k,v,indent)
    end
end

--[[
function logTable(t,pre)
282 283 284 285 286 287 288
local pre = pre or ""
for k,v in pairs(t) do
vlc.msg.err(pre..tostring(k).." : "..tostring(v))
if type(v) == "table" then
a(v,pre.."  ")
end
end
289 290 291 292 293 294
end
--]]

--main accessors

getplaylist = function ()
295 296 297
    local p

    if _GET["search"] then
298 299 300 301 302 303 304
        if _GET["search"] ~= "" then
            _G.search_key = _GET["search"]
        else
            _G.search_key = nil
        end
        local key = vlc.strings.decode_uri(_GET["search"])
        p = vlc.playlist.search(key)
305
    else
306
        p = vlc.playlist.get()
307 308 309 310 311
    end

    --logTable(p) --Uncomment to debug

    return p
312 313 314
end

parseplaylist = function (item)
315
    if item.flags.disabled then return end
316

317 318 319
    if (item.children) then
        local result={}
        local name = (item.name or "")
320

321 322 323 324
        result["type"]="node"
        result.id=tostring(item.id)
        result.name=tostring(name)
        result.ro=item.flags.ro and "ro" or "rw"
325

326 327 328 329
        --store children in an array
        --we use _array as a proxy for arrays
        result.children={}
        result.children._array={}
330

331 332
        for _, child in ipairs(item.children) do
            local nextChild=parseplaylist(child)
333
            table.insert(result.children._array,nextChild)
334 335
        end

336 337 338 339 340
        return result
    else
        local result={}
        local name, path = item.name or ""
        local path = item.path or ""
341
        local current_item_id = vlc.playlist.current()
342

343
        -- Is the item the one currently played
344 345
        if(current_item_id ~= nil) then
            if(current_item_id == item.id) then
346 347 348
                result.current = "current"
            end
        end
349

350 351 352 353 354 355
        result["type"]="leaf"
        result.id=tostring(item.id)
        result.uri=tostring(path)
        result.name=name
        result.ro=item.flags.ro and "ro" or "rw"
        result.duration=math.floor(item.duration)
356

357 358
        return result
    end
359 360 361 362 363

end

playlisttable = function ()

364
    local basePlaylist=getplaylist()
365

366
    return parseplaylist(basePlaylist)
367 368
end

369 370
getbrowsetable = function ()

371 372 373 374
    local dir = nil
    local uri = _GET["uri"]
    --uri takes precedence, but fall back to dir
    if uri then
375 376 377 378 379
        if uri == "file://~" then
            dir = uri
        else
            dir = vlc.strings.make_path(uri)
        end
380 381 382 383 384 385
    else
        dir = _GET["dir"]
    end

    --backwards compatibility with old format driveLetter:\\..
    --this is forgiving with the slash type and number
386 387 388 389
    if dir then
        local position=string.find(dir, '%a:[\\/]*%.%.',0)
        if position==1 then dir="" end
    end
390 391 392 393 394 395 396

    local result={}
    --paths are returned as an array of elements
    result.element={}
    result.element._array={}

    if dir then
397
        if dir == "~" or dir == "file://~" then dir = vlc.config.homedir() end
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
        -- FIXME: hack for Win32 drive list
        if dir~="" then
            dir = common.realpath(dir.."/")
        end

        local d = vlc.net.opendir(dir)
        table.sort(d)

        for _,f in pairs(d) do
            if f == ".." or not string.match(f,"^%.") then
                local df = common.realpath(dir..f)
                local s = vlc.net.stat(df)
                local path, name =  df, f
                local element={}

413 414 415 416 417 418
                if (s) then
                    for k,v in pairs(s) do
                        element[k]=v
                    end
                else
                    element["type"]="unknown"
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
                end
                element["path"]=path
                element["name"]=name

                local uri=vlc.strings.make_uri(df)
                --windows paths are returned with / separators, but make_uri expects \ for windows and returns nil
                if not uri then
                    --convert failed path to windows format and try again
                    path=string.gsub(path,"/","\\")
                    uri=vlc.strings.make_uri(df)
                end
                element["uri"]=uri

                table.insert(result.element._array,element)
            end

        end
    end

    return result;
439 440
end

441 442 443 444

getstatus = function (includecategories)


445 446 447 448 449
    local input = vlc.object.input()
    local item = vlc.input.item()
    local playlist = vlc.object.playlist()
    local vout = vlc.object.vout()
    local aout = vlc.object.aout()
450

451 452 453
    local s ={}

    --update api version when new data/commands added
454
    s.apiversion=3
455 456 457 458
    s.version=vlc.misc.version()
    s.volume=vlc.volume.get()

    if input then
459
        s.time=math.floor(vlc.var.get(input,"time") / 1000000)
460
        s.position=vlc.var.get(input,"position")
461
        s.currentplid=vlc.playlist.current()
462
        s.audiodelay=vlc.var.get(input,"audio-delay") / 1000000
463
        s.rate=vlc.var.get(input,"rate")
464
        s.subtitledelay=vlc.var.get(input,"spu-delay") / 1000000
465 466 467
    else
        s.time=0
        s.position=0
468
        s.currentplid=-1
469 470 471 472 473
        s.audiodelay=0
        s.rate=1
        s.subtitledelay=0
    end

474 475 476 477 478 479
    if item then
        s.length=math.floor(item:duration())
    else
        s.length=0
    end

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    if vout then
        s.fullscreen=vlc.var.get(vout,"fullscreen")
        s.aspectratio=vlc.var.get(vout,"aspect-ratio");
        if s.aspectratio=="" then s.aspectratio = "default" end
    else
        s.fullscreen=0
    end

    if aout then
        local filters=vlc.var.get(aout,"audio-filter")
        local temp=strsplit(filters,":")
        s.audiofilters={}
        local id=0
        for i,j in pairs(temp) do
            s.audiofilters['filter_'..id]=j
            id=id+1
        end
    end

    s.videoeffects={}
    s.videoeffects.hue=round(vlc.config.get("hue"),2)
    s.videoeffects.brightness=round(vlc.config.get("brightness"),2)
    s.videoeffects.contrast=round(vlc.config.get("contrast"),2)
    s.videoeffects.saturation=round(vlc.config.get("saturation"),2)
    s.videoeffects.gamma=round(vlc.config.get("gamma"),2)

    s.state=vlc.playlist.status()
    s.random=vlc.var.get(playlist,"random")
    s.loop=vlc.var.get(playlist,"loop")
    s["repeat"]=vlc.var.get(playlist,"repeat")
510

511 512 513 514 515 516 517
    s.equalizer={}
    s.equalizer.preamp=round(vlc.equalizer.preampget(),2)
    s.equalizer.bands=vlc.equalizer.equalizerget()
    if s.equalizer.bands ~= null then
        for k,i in pairs(s.equalizer.bands) do s.equalizer.bands[k]=round(i,2) end
        s.equalizer.presets=vlc.equalizer.presets()
    end
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

    if (includecategories and item) then
        s.information={}
        s.information.category={}
        s.information.category.meta=item:metas()

        local info = item:info()
        for k, v in pairs(info) do
            local streamTable={}
            for k2, v2 in pairs(v) do
                local tag = string.gsub(k2," ","_")
                streamTable[tag]=v2
            end

            s.information.category[k]=streamTable
        end

        s.stats={}

        local statsdata = item:stats()
538
        for k,v in pairs(statsdata) do
539
            local tag = string.gsub(k,"_","")
540 541
            s.stats[tag]=v
        end
542

543 544
        s.information.chapter=vlc.var.get(input, "chapter")
        s.information.title=vlc.var.get(input, "title")
545

546 547
        s.information.chapters=vlc.var.get_list(input, "chapter")
        s.information.titles=vlc.var.get_list(input, "title")
548

549 550
    end
    return s
551
end
552