Documenting cli.lua - a stripped console-only CLI
Posted: 07 Mar 2015 05:37
Pardon me if I am still in the wrong forum. Put this where it belongs if necessary. I posted an earlier version of this in "scripting
VLC with Lua", and I can put it back there.
The copyright notice is adapted from host.lua.
Edit:
The main loop can also be written like this:
This enables making the script more verbose (not that I want that feature for myself):
VLC with Lua", and I can put it back there.
The copyright notice is adapted from host.lua.
Code: Select all
--[==========================================================================[
shell.lua: A stripped console-only CLI for documentation
--[==========================================================================[
Copyright (C) 2015 nokangaroo nokangaroo@NOSPAM.aon.at
Work in progress
Based on host.lua and cli.lua
host.lua author: Antoine Cellerier <dionoea at videolan dot org>
cli.lua authors: Antoine Cellerier <dionoea at videolan dot org>
Pierre Ynard
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.
--]==========================================================================]
running = true
function quit()
vlc.misc.quit()
running = false
end
--Begin user-defined functions
--[==========================================================================[
The input buffer is split into the global table "val"; val[0] is the function
itself, val[1] ... val[n] is a variable number of arguments. There is no error
handling (yet); you will have to restart vlc after every typo, but this script
is mainly intended for receiving machine-generated input from a fifo.
Test this interface with:
luac5.1 <this file>
mkdir -p $HOME/.local/share/vlc/lua/intf
mv luac.out $HOME/.local/share/vlc/lua/intf/shell.luac
vlc -I "luaintf{intf=shell}" 2>/dev/null /path/to/media
or:
mkfifo fifo
exec 3<> fifo
vlc <&3 -I "luaintf{intf=shell}" /path/to/media
#Command examples:
set_var input chapter +1
set_var vout crop 16:9
set_var input time +100
write_var input title /path/to/<disc_id>.dvdbookmarks
echo set_var input time 123.456 > fifo
set_var input title 0 #go to DVD menu
--]==========================================================================]
function help()
local t =
[[
********************************************************************************
Available commands (the values can be float or int according to the command):
set_time <value> alias for set_var input time <value>
set_var <object> <variable> <value> set a variable (objects are input, aout,
vout; variables are title, time, length,
crop, zoom, aspect-ratio, rate)
track <audio-es|spu-es> <value> set audio or subtitle track
write_var <object> <variable> <path> write the value of a variable to a file
write_var volume <path>
volume <value>
pause
play
help
quit
set_var and volume also allow incremental values (+-<value>)
********************************************************************************
]]
print(t)
end
function set_time() --e.g. set_time 123.456
local val = val[1]
local input = vlc.object.input()
local check = (vlc.var.get(input,"length") - val)
if val and check > 0 then
vlc.var.set(input,"time",val)
end
end
function set_var() --e.g. set_var input time 123.456
local obj = val[1]
local var = val[2]
local value = val[3] --float or int depending on var
local o
if obj == "input" then
o = vlc.object.input()
elseif obj == "aout" then
o = vlc.object.aout()
elseif obj == "vout" then
o = vlc.object.vout()
end
if type(value) == "string" and string.sub(value,1,1) == "+" or string.sub(value,1,1) == "-" then
local old = tonumber(vlc.var.get(o,var))
vlc.var.set(o,var,(old + tonumber(value)))
else
vlc.var.set(o,var,value)
end
end
--write variables to file
--[[for importing variables in shell scripts use something like this:
get_var() {
local i
cat /dev/null > $TMP
for i in "$@"; do
echo "write_var input $i $TMP" > $FIFO
done
eval `cat $TMP`
}
]]
function write_var() --e.g. write_var input title <path> or write_var volume <path>
local obj = val[1]
local var = val[2]
local path
local value
local o
if obj == "input" then
o = vlc.object.input()
elseif obj == "aout" then
o = vlc.object.aout()
elseif obj == "vout" then
o = vlc.object.vout()
end
if obj == "volume" then
path = var
var = obj
value = vlc.volume.get()
else
path = val[3]
value = vlc.var.get(o,var)
end
local file = io.open(tostring(path), "a+")
file:write(tostring(var) .. '=' .. tostring(value) .. '\n')
file:close()
end
--audio track and subtitle track
--[[The listvalue function in cli.lua is bogus because elementary streams can
change on DVDs when switching back and forth between titlesets. The order of
tracks in the track list remains constant though; so we need to grep for the
matching track and then set audio-es or spu-es to the value in the 1st column.]]
function track() --e.g. track audio-es 3 or track spu-es 0
local var = val[1]
local value = val[2]
local o = vlc.object.input()
if not value or tostring(value) == "0" then --mute audio, disable sub
vlc.var.set(o,var,-1) --or 0
return
end
local str1 = string.format("Track %s", tostring(value))
local v,l = vlc.var.get_list(o,var)
local val
for i,val in ipairs(v) do
local str = tostring(val) .. tostring(l[i])
if string.match(str,str1) then
local t = string.match(str,"^%d+")
vlc.var.set(o,var,t)
break
end
end
end
function volume() --e.g. volume 100 or volume +10
local value = val[1]
if type(value) == "string" and string.sub(value,1,1) == "+" or string.sub(value,1,1) == "-" then
vlc.volume.set(vlc.volume.get() + tonumber(value))
else
vlc.volume.set(tostring(value))
end
end
function pause()
vlc.playlist.pause()
end
function play()
vlc.playlist.play()
end
--End user-defined functions
--Utility: split buffer at word boundaries
--Add stuff to the regex in string.gmatch if needed
function split_input(str)
local j = 0
val = {}
for i in string.gmatch(str,"[%w_/%-%+%.:]+") do
val[j] = i
--num_args = j
j = j+1
end
end
--???????????????????????????????????????
--Can someone explain what these are for?
--function on_read(client)
--end
--function on_write(client)
--end
--???????????????????????????????????????
require "host"
h = host.host()
-- Bypass any authentication
function on_password(client)
client:switch_status(host.status.read)
end
h.status_callbacks[host.status.password] = on_password
--h.status_callbacks[host.status.read] = on_read
--h.status_callbacks[host.status.write] = on_write
h:listen("*console")
-- The main loop (cribbed from cli.lua and host.lua)
while running do
-- accept new connections and select active clients
local write,read = h:accept_and_select()
-- handle clients in write mode
for _, client in pairs(write) do
--this enables writing on the console:
local len = client:send()
client.buffer = string.sub(client.buffer,len + 1)
if client.buffer == "" then client:switch_status(host.status.read) end
end
-- handle clients in read mode
for _, client in pairs(read) do
local input = client:recv(1000) --[[this seems to be the number of bytes
received. If so, could probably be less for a pure console interface]]
if not input then break end
client.cmds = input .. '\n'
--client.buffer = client.cmds --this will echo the commands
client.buffer=""
client:switch_status(host.status.write)
split_input(client.cmds)
--execute the command:
_G[val[0]]()
end
end
The main loop can also be written like this:
Code: Select all
while running do
-- accept new connections and select active clients
local write,read = h:accept_and_select()
-- handle clients in write mode
for _, client in pairs(write) do
client:send()
client:switch_status(host.status.read)
end
-- handle clients in read mode
for _, client in pairs(read) do
local input = client:recv(1000) --[[this seems to be the number of bytes
received. If so, could probably be less for a pure console interface]]
if not input then break end
client.cmds = input
--client.buffer = client.cmds --this will echo the commands
--client.buffer=""
--client:append(client.cmds) --can be redirected to file
client:append(client.buffer) --can be redirected to file
client:switch_status(host.status.write)
split_input(client.cmds)
--nil=play and nil=pause won't give an error:
--local string = tostring(val[num_args - 1]) .. "=" .. tostring(val[num_args])
--client:append(string)
--execute the command:
_G[val[0]](client)
end
end
Code: Select all
function volume(client) --e.g. volume 100 or volume +10
local value = val[1]
if type(value) == "string" and string.sub(value,1,1) == "+" or string.sub(value,1,1) == "-" then
vlc.volume.set(vlc.volume.get() + tonumber(value))
else
vlc.volume.set(tostring(value))
end
local volume = "volume=" .. (vlc.volume.get())
client:append(volume)
end