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

lua, vlc

Solution

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

Problem

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?

Original source