Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write a plugin for VLC that responds to play, pause and stop events?

Tags:

lua

vlc

I'd like to write a very simple plugin for VLC that makes web requests when a media is played, paused, or stopped. It is a very similar to a scrobbling plugin .

I saw that VLC supports plugin and extensions (which are very simple Lua scripts) but I haven't been able to find any information on how to do this.

I guess I'd need to write a plugin that registers some callbacks -- am I right? Any idea on how I could accomplish this? It seems to be quite an uphill battle figuring this out. Can I do this using Python?

like image 468
Mridang Agarwalla Avatar asked Apr 03 '13 18:04

Mridang Agarwalla


1 Answers

I'm using VLC 2.2.1 on Windows.

Here's a simple Lua plugin that recognizes play/pause/stop events:

function descriptor()
  return {
    title = "VLC Dummy Extension",
    capabilities = { "playing-listener" }
  }
end

function activate()
end

function deactivate()
end

function meta_changed()
end

function playing_changed()
  vlc.msg.dbg("[Dummy] Status: " .. vlc.playlist.status())
end

Notes:

  • VLC will call activate(), deactivate(), meta_changed() at some point in the plugin life cycle. You're not required to include them, but VLC will fill up your debug log with useless "function not found" messages.
  • If the plugin's capabilities contain playing-listener, VLC will expect the playing_changed() hook and call it when appropriate (even though the code comment says the hook name is "status_changed").
  • vlc.playlist.status() returns "stopped", "playing", "paused" or "unknown".

Run:

  • Save the plugin in a .lua file, then drop it in VLC's extensions folder: %APPDATA%\vlc\lua\extensions\ (Windows) or ~/.local/share/vlc/lua/extensions/ (Linux).
  • Load it by Tools > Plugins and extensions, Reload extensions (restarting VLC is unnecessary).
  • Activate it (there's an option under View, named after title in the plugin descriptor); activate() will be called.
  • To view all logs (vlc.msg calls), open Tools > Messages (Ctrl+M), set the level to debug and filter by "lua".

To do something whenever a new item plays:

  • Add input-listener to the plugin's capabilities.
  • Add the corresponding hook input_changed().
  • Use vlc.input.item() to get the current item (name, URI, metadata, etc).
  • You can post what's playing to an HTTP server. VLC offers vlc.net, which means you have to program for sockets. Fortunately, the extension vlsub, shipped with VLC by default, has utility methods for sending GET requests. We can steal those.

In this example, I'm just sending a threadbare GET:

http://127.0.0.1:5000/?name=MMFR.2015.720p.mp4

If I don't care about redirects or reading responses, get() is a lot simpler than the vlsub's version:

function descriptor()
  return {
    title = "VLC Dummy Extension",
    capabilities = { "input-listener" }
  }
end

function activate()
end

function deactivate()
end

function meta_changed()
end

function input_changed()
  if vlc.input.is_playing() and vlc.playlist.status() == "playing" then
    local item = vlc.input.item()
    if item then
      vlc.msg.dbg("[Dummy] Now playing: " .. item:name())
      get("http://127.0.0.1:5000/?name=" .. item:name())
    end
  end
end

function get(url)
  local u = vlc.net.url_parse(url)
  local host, port, path = u["host"], u["port"], u["path"]
  local header = {
    "GET "..path.." HTTP/1.1",
    "Host: "..host,
    "",
    ""
  }
  local request = table.concat(header, "\r\n")
  http_req(host, port, request)
end

function http_req(host, port, request)
  local fd = vlc.net.connect_tcp(host, port)
  if not fd then return false end
  local pollfds = {}

  pollfds[fd] = vlc.net.POLLIN
  vlc.net.send(fd, request)
  vlc.net.poll(pollfds)

  local chunk = vlc.net.recv(fd, 2048)
  while chunk do
    vlc.net.poll(pollfds)
    chunk = vlc.net.recv(fd, 1024)
  end
  vlc.net.close(fd)
end
like image 159
approxiblue Avatar answered Sep 29 '22 13:09

approxiblue