Page 1 of 1

[Interface] Hotkeys

Posted: 26 Jun 2013 13:16
by mederi
It is possible to define custom hotkeys and actions using the hotkeys Lua interface script.

Original hotkeys demo interface script:

Code: Select all

--[==========================================================================[ hotkeys.lua: hotkey handling for VLC --[==========================================================================[ Copyright (C) 2007 the VideoLAN team $Id$ Authors: Antoine Cellerier <dionoea at videolan dot org> 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. --]==========================================================================] --[==========================================================================[ This is meant to replace modules/control/hotkeys.c (which will require some changes in the VLC core hotkeys stuff) --]==========================================================================] require("common") --common.table_print(vlc,"vlc.\t") bindings = { ["Ctrl-q"] = "quit", ["Space"] = "play-pause", [113] --[[q]] = "quit", [119] --[[w]] = "demo", [120] --[[x]] = "demo2", } function quit() print("Bye-bye!") vlc.misc.quit() end function demo() vlc.osd.icon("speaker") end function demo2() if not channel1 then channel1 = vlc.osd.channel_register() channel2 = vlc.osd.channel_register() end vlc.osd.message("Hey!",channel1) vlc.osd.slider( 10, "horizontal", channel2 ) end function action(func,delta) return { func = func, delta = delta or 0, last = 0, times = 0 } end actions = { ["quit"] = action(quit), ["play-pause"] = action(play_pause), ["demo"] = action(demo), ["demo2"] = action(demo2), } action = nil queue = {} function action_trigger( action ) print("action_trigger:",tostring(action)) local a = actions[action] if a then local ok, msg = pcall( a.func ) if not ok then vlc.msg.err("Error while executing action `".. tostring(action) .."': "..msg) end else vlc.msg.err("Key `"..key.."' points to unknown action `"..bindings[key].."'.") end end function key_press( var, old, key, data ) print("key_press:",tostring(key)) if bindings[key] then action_trigger(bindings[key]) else vlc.msg.err("Key `"..key.."' isn't bound to any action.") end end vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press ) --vlc.var.add_callback( vlc.object.libvlc(), "action-triggered", action_trigger ) while not vlc.misc.lock_and_wait() do end -- Clean up vlc.var.del_callback( vlc.object.libvlc(), "key-pressed", key_press ) --vlc.var.del_callback( vlc.object.libvlc(), "action-triggered", action_trigger )
An abstract:

Code: Select all

function key_press( var, old, key, data ) if key==120 then -- "x" key was pressed, do something end end vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press )
hotkeys.lua - an example of usage:
x = Rewind = Play from the start
t = OSD Codec Information and Name = Show Codec Information and Name on the screen in a playing video

Code: Select all

mtitle = "[hotkeys]" function Log(m) vlc.msg.info(mtitle.." "..m) end -- Play from the start function Rewind(m) Log(m) local input=vlc.object.input() if input then vlc.var.set(input, "time", 0) end end -- Show Codec Information and Name on the screen in a playing video t=10 -- seconds t0=-t function OSD_Codec_Info(m) Log(m) t1=os.clock() if t1>(t0+t) then t0=t1 local input_item = vlc.input.item() if input_item then local info_table = input_item:info() local info_output = "Codec Information:\n" for k0,v0 in pairs(info_table) do info_output = info_output .. ">> " .. k0 .. ": " for _,v1 in pairs(v0) do info_output = info_output .. v1 .. ", " end info_output = string.gsub(info_output, "^(.*), $", "%1;") info_output = info_output .. "\n" end channel1 = vlc.osd.channel_register() channel2 = vlc.osd.channel_register() vlc.osd.message(info_output,channel1,"top-left",t*1000000) vlc.osd.message(input_item:name(),channel2,"bottom",t*1000000) end else t0=-t vlc.osd.message("",channel1) vlc.osd.message("",channel2) end end function key_press( var, old, key, data ) Log("Key code: " .. key) if key==116 then OSD_Codec_Info("t = OSD Codec Information and Name") end if key==120 then Rewind("x = Rewind") end end vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press )
Installation (VLC-2.0.x, Windows):
1.) Find "hotkeys.luac" file in VLC in your computer (lua\intf\hotkeys.luac) and replace it with your custom script "hotkeys.lua".
2.) Tools > Preferences > ( Show settings = All ) > Interface \ Main interfaces: [luaintf] = write "luaintf" (without quotes) in the text input field
Tools > Preferences > ( Show settings = All ) > Interface \ Main interfaces \ Lua: Lua interface [hotkeys]
3.) Save changes, restart VLC, enjoy :)
Image
Or you can use CLI (batch file or desktop shortcut icon) instead of preferences:

Code: Select all

vlc.exe --extraintf=luaintf --lua-intf=hotkeys
Please share your ideas and enhancements of the script here.

Re: Hotkeys - Interface script

Posted: 06 Feb 2014 13:45
by mederi
q -> OSD Codec Information and Name
t -> OSD OS Time
x -> Rewind
Shift+Ctrl+Delete -> Delete current file
Ctrl+x -> Bookmark: Remember current media and playback position
Shift+x -> Bookmark: Open remembered media and playback position
Shift+Ctrl+x -> Bookmark: Delete bookmark

Code: Select all

-- hotkeys.lua -- VLC-2.0.x Interface script -- logger function Log(m) vlc.msg.info("[hotkeys] " .. m) end -- Remember current item and actual playback position function Bookmark(action, m) Log(m) if action=="save" then item = vlc.input.item() status = vlc.playlist.status() if item and (status=="playing" or status=="paused") then uri = item:uri() local input=vlc.object.input() if input then uri = uri .. "#" .. vlc.var.get(input, "time") end Log("Create bookmark: " .. uri) vlc.config.set("bookmark1", uri) if vlc.object.vout() then bchannel = vlc.osd.channel_register() vlc.osd.message("Bookmark:\n" .. uri,bchannel,"centre",5000000) end end elseif action=="load" then buritime = vlc.config.get("bookmark1") if buritime then buri, btime = string.match(buritime, "^(.*)#(.-)$") Log("Open bookmark:\nuri=" .. tostring(buri or buritime) .. "\ntime=" .. tostring(btime)) vlc.playlist.add({{path=buri or buritime}}) if btime then vlc.misc.mwait(vlc.misc.mdate()+500000) local input=vlc.object.input() if input then vlc.var.set(input, "time", btime) end end end else -- action=="clear" vlc.config.set("bookmark1", "") if vlc.object.vout() then bchannel = vlc.osd.channel_register() vlc.osd.message("Bookmark deleted",bchannel,"centre",3000000) end end end -- detect OS type local winDir = os.getenv("windir") if winDir~=nil and winDir~="" then Windows=true end -- Delete current file function Delete(m) Log(m) item = vlc.input.item() status = vlc.playlist.status() if item and (status=="playing" or status=="paused") then uri = item:uri() uri = vlc.strings.decode_uri(uri) --filepath = string.sub(filepath,9) filepath = string.match(uri, "^file:///(.+)$") if filepath~=nil then if Windows then -- Windows style path filepath = string.gsub(filepath, "/", "\\") else -- Linux style path filepath = "/" .. filepath end Log("Selected for deletion: " .. filepath) else Log("NOT A FILE: " .. uri) end currentID = vlc.playlist.current() -- play next media item to realease the current one for deletion vlc.playlist.next() else filepath=nil currentID=nil end -- wait for a while, hopefully Windows releases the file for deletion vlc.misc.mwait(vlc.misc.mdate()+1000000) -- delete item from playlist newID = vlc.playlist.current() if currentID then if currentID == newID then -- only one item in playlist, so stop it and wait for a while vlc.playlist.stop() vlc.misc.mwait(vlc.misc.mdate()+1000000) end vlc.playlist.delete(currentID-1) currentID=nil Log("PLAYLIST ITEM DELETED") end -- delete file if filepath~=nil then retval, err = os.remove(filepath) if(retval == nil) -- error handling; if deletion failed, print why then Log("ERROR DELETING FILE: " .. tostring(err)) -- write in a text file... else Log("FILE DELETED") end filepath=nil end end -- Play from the start function Rewind(m) Log(m) local input=vlc.object.input() if input then vlc.var.set(input, "time", 0) end end -- Show OS time in a playing video ot=5 ot0=-ot function OSD_Time(m) ot1=os.clock() if ot1>(ot0+ot) then ot0=ot1 Log(m) local channel1 = vlc.osd.channel_register() vlc.osd.message(" \n\n"..os.date("%H:%M:%S"),channel1,"top-right",ot*1000000) end end -- Show Codec Information and Name on the screen in a playing video t=10 -- seconds t0=-t function OSD_Codec_Info(m) Log(m) t1=os.clock() if t1>(t0+t) then t0=t1 local input_item = vlc.input.item() if input_item then local info_table = input_item:info() local info_output = "Codec Information:\n" for k0,v0 in pairs(info_table) do info_output = info_output .. "_" .. k0 .. ": " for _,v1 in pairs(v0) do info_output = info_output .. v1 .. ", " end info_output = string.gsub(info_output, "^(.*), $", "%1;") info_output = info_output .. "\n" end channel1 = vlc.osd.channel_register() channel2 = vlc.osd.channel_register() vlc.osd.message(info_output,channel1,"top-left",t*1000000) vlc.osd.message(input_item:name(),channel2,"bottom",t*1000000) end else t0=-t vlc.osd.message("",channel1) vlc.osd.message("",channel2) end end function key_press( var, old, key, data ) Log("Key code: " .. key) if key==113 then OSD_Codec_Info("q -> OSD Codec Information and Name") end if key==116 then OSD_Time("t -> OSD OS Time") end if key==120 then Rewind("x -> Rewind") end if key==104202240 then Delete("Shift+Ctrl+Delete -> Delete current file") end if key==67108984 then Bookmark("save", "Ctrl+x -> Bookmark: Remember current media and playback position") end if key==33554552 then Bookmark("load", "Shift+x -> Bookmark: Open remembered media and playback position") end if key==100663416 then Bookmark("clear", "Shift+Ctrl+x -> Bookmark: Delete bookmark") end end vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press )

Snapshot webradio info to log file.

Posted: 12 Aug 2014 19:56
by mederi
The idea from https://forum.videolan.org/viewtopic.php?f=29&t=120575
Here is a new function for Hotkeys script:

Code: Select all

-- Snapshot webradio info (Now Playing metatag) to log file. function Now_Playing_Snapshot(m) Log(m) local path="d:\\nplist.txt" local input_item = vlc.input.item() if not input_item then return end local metas_table = input_item:metas() if metas_table.now_playing==nil then return end local file, err, code = io.open(path, "a+") if file then file:write(os.date("%Y-%m-%d %H:%M:%S > ") .. metas_table.now_playing .. "\n") file:close() end end

Code: Select all

... if key==67108913 then Now_Playing_Snapshot("Ctrl+1 -> Write Now Playing metatag to log file") end ...

Re: Hotkeys - Interface script

Posted: 31 Aug 2014 20:07
by Gerxu
Hello mederi!

I really like your extension subtitler (lite) https://forum.videolan.org/viewtopic.php?f=29&t=97791. It works great in my 2.0.8 VLC.

But now that I see this hotkeys topic, I was wondering if it's possible define an action to toggle (open/close) your subtitler extension with a hotkey.

Thank you very much!

Re: Hotkeys - Interface script

Posted: 01 Sep 2014 11:58
by mederi
I really do not know whether it is possible to trigger an extension from interface script. I would like to know the answer, too. Some C++ programmer could look at the case.

Subtitler

Posted: 01 Sep 2014 19:36
by mederi
Here is modified Subtitler (lite) you could use within the hotkeys interface script. Dialog box is not available here.

Code: Select all

-- Subtitler (lite) -- Global variables: subtitles_path = nil -- "D:/films/subtitles.srt" osd_position = "top" -- "top-left", "top-right", "left", ... charset = "Windows-1250" -- nil or "UTF-8", "ISO-8859-2", ... function media_path(extension) local media_uri = vlc.input.item():uri() media_uri = vlc.strings.decode_uri(media_uri) media_uri = string.gsub(media_uri, "^.-///(.*)%..-$","%1") --- dir_sep = package.config:sub(1,1) or '/' if dir_sep=="/" then media_uri = "/" .. media_uri end -- Linux style path --- media_uri = media_uri.."."..extension vlc.msg.info(media_uri) return media_uri end function format_time(h,m,s,ms) -- time to seconds return tonumber(h)*3600+tonumber(m)*60+tonumber(s)+tonumber("."..ms) end function Load_subtitles() if subtitles_path==nil then subtitles_path=media_path("srt") end -- read file local file = io.open(subtitles_path, "r") if file==nil then return false end --data = file:read("*a") data = file:read(500000) file:close() -- parse data subtitles={} srt_pattern = "(%d%d):(%d%d):(%d%d),(%d%d%d) %-%-> (%d%d):(%d%d):(%d%d),(%d%d%d).-\n(.-)\n\n" for h1, m1, s1, ms1, h2, m2, s2, ms2, text in string.gmatch(data, srt_pattern) do if text=="" then text=" " end if charset~=nil then text=vlc.strings.from_charset(charset, text) end table.insert(subtitles,{format_time(h1, m1, s1, ms1), format_time(h2, m2, s2, ms2), text}) end if #subtitles~=0 then return true else return false end end subtitle=nil function input_events_handler(var, old, new, data) local input = vlc.object.input() local actual_time = vlc.var.get(input, "time") if subtitle==nil then for i,v in pairs(subtitles) do if actual_time>=v[1] and actual_time<=v[2] then --vlc.msg.info(actual_time.." << subtitle on") subtitle=v vlc.osd.message(subtitle[3],channel1,osd_position) --vlc.msg.info(subtitle[3]) break end end else if actual_time<subtitle[1] or actual_time>subtitle[2] then --vlc.msg.info(actual_time.." << subtitle off") subtitle=nil vlc.osd.message("",channel1) else vlc.osd.message(subtitle[3],channel1,osd_position) -- OSD subtitle refresh end end end Subtitler_callback=false function Subtitler(m) Log(m) if not Subtitler_callback then if vlc.object.vout() and vlc.input.item() and Load_subtitles() then channel1 = vlc.osd.channel_register() local input = vlc.object.input() Subtitler_callback=true vlc.var.add_callback(input, "intf-event", input_events_handler, "Hello world!") end else Subtitler_callback=false local input = vlc.object.input() vlc.var.del_callback(input, "intf-event", input_events_handler, "Hello world!") end end

Code: Select all

... if key==67108914 then Subtitler("Ctrl+2 -> Subtitler") end ...

Re: Hotkeys - Interface script

Posted: 05 Sep 2014 21:22
by Gerxu
Thank you very much! Works like a charm. I also changed this line:

Code: Select all

if subtitles_path==nil then subtitles_path=media_path("srt") end
for

Code: Select all

subtitles_path=media_path("srt")
Just to reload new subtitles when I change the media source. It doesn't look very well optimized...but whatever.

In case someone wants to know what I use this for... I use VLSub to download both Spanish and English subtitles with the option 'display language code in file name' checked. Then I use this hotkeys interface script like mederi said (whole file):

Code: Select all

mtitle = "[hotkeys]" function Log(m) vlc.msg.info(mtitle.." "..m) end -- Subtitler (lite) -- Global variables: subtitles_path = nil -- "D:/films/subtitles.srt" osd_position = "top" -- "top-left", "top-right", "left", ... charset = "Windows-1250" -- nil or "UTF-8", "ISO-8859-2", ... function media_path(extension) local media_uri = vlc.input.item():uri() media_uri = vlc.strings.decode_uri(media_uri) media_uri = string.gsub(media_uri, "^.-///(.*)%..-$","%1") dir_sep = package.config:sub(1,1) or '/' if dir_sep=="/" then media_uri = "/" .. media_uri end -- Linux style path media_uri = media_uri..".spa."..extension vlc.msg.info(media_uri) return media_uri end function format_time(h,m,s,ms) -- time to seconds return tonumber(h)*3600+tonumber(m)*60+tonumber(s)+tonumber("."..ms) end function Load_subtitles() subtitles_path=media_path("srt") -- read file local file = io.open(subtitles_path, "r") if file==nil then return false end --data = file:read("*a") data = file:read(500000) file:close() -- parse data subtitles={} srt_pattern = "(%d%d):(%d%d):(%d%d),(%d%d%d) %-%-> (%d%d):(%d%d):(%d%d),(%d%d%d).-\n(.-)\n\n" for h1, m1, s1, ms1, h2, m2, s2, ms2, text in string.gmatch(data, srt_pattern) do if text=="" then text=" " end if charset~=nil then text=vlc.strings.from_charset(charset, text) end table.insert(subtitles,{format_time(h1, m1, s1, ms1), format_time(h2, m2, s2, ms2), text}) end if #subtitles~=0 then return true else return false end end subtitle=nil function input_events_handler(var, old, new, data) local input = vlc.object.input() local actual_time = vlc.var.get(input, "time") if subtitle==nil then for i,v in pairs(subtitles) do if actual_time>=v[1] and actual_time<=v[2] then --vlc.msg.info(actual_time.." << subtitle on") subtitle=v vlc.osd.message(subtitle[3],channel1,osd_position) --vlc.msg.info(subtitle[3]) break end end else if actual_time<subtitle[1] or actual_time>subtitle[2] then --vlc.msg.info(actual_time.." << subtitle off") subtitle=nil vlc.osd.message("",channel1) else vlc.osd.message(subtitle[3],channel1,osd_position) -- OSD subtitle refresh end end end Subtitler_callback=false function Subtitler(m) Log(m) if not Subtitler_callback then if vlc.object.vout() and vlc.input.item() and Load_subtitles() then channel1 = vlc.osd.channel_register() local input = vlc.object.input() Subtitler_callback=true vlc.var.add_callback(input, "intf-event", input_events_handler, "Hello world!") end else Subtitler_callback=false local input = vlc.object.input() vlc.var.del_callback(input, "intf-event", input_events_handler, "Hello world!") end end function key_press( var, old, key, data ) if key==120 then Subtitler("x -> Subtitler") end end vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press )
As you can see in this line, I always load .spa subtitles:

Code: Select all

media_uri = media_uri..".spa."..extension
So now I can play a media and improve my English with English subtitles and activate and deactivate top Spanish subtitles to check some words that I don't know.

Re: Hotkeys - Interface script

Posted: 06 Sep 2014 12:54
by mederi
Good example how to install, customize and use the script. Thanks.
For your Spanish environment I would just do this:

Code: Select all

subtitles_path = nil osd_position = "top" charset = "Windows-1252" filename_extension = "spa.srt" ... if subtitles_path==nil then subtitles_path=media_path(filename_extension) end ...
Sometimes you need to set the charset to nil, as some subtitle files can be already "UTF-8" encoded. You could implement automatic recognition of BOM of UTF-8 or you could implement another hotkey to switch among "Windows-1252", "ISO-8859-1" and "UTF-8" charsets. :)
I do not know whether it is possible to hang some callback on input-change event in interface script just like it is in extension script.

Re: Hotkeys - Interface script

Posted: 16 Jun 2017 05:50
by qazwiz

So now I can play a media and improve my English with English subtitles and activate and deactivate top Spanish subtitles to check some words that I don't know.
I applaud your ingenuity. i know a guy who learned English from TV but I bet the duo subtitles expedites the process