Last active
March 6, 2024 17:51
-
-
Save progandy/dc50c4b9a74cc8c74f816a500c7a7d87 to your computer and use it in GitHub Desktop.
Minimal MPRIS2 support for mpv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local lgi = require 'lgi' | |
local GObject = lgi.require 'GObject' | |
local Gio = lgi.require 'Gio' | |
local GLib = lgi.require 'GLib' | |
local core = require 'lgi.core' | |
local mp = require "mp" | |
local MPRIS2_OBJPATH = "/org/mpris/MediaPlayer2" | |
local xml = [[<?xml version="1.0" encoding="UTF-8"?> | |
<node> | |
<interface name="org.freedesktop.DBus.Introspectable"> | |
<method name="Introspect"> | |
<arg name="data" direction="out" type="s"/> | |
</method> | |
</interface> | |
<interface name="org.freedesktop.DBus.Properties"> | |
<method name="Get"> | |
<arg direction="in" type="s"/> | |
<arg direction="in" type="s"/> | |
<arg direction="out" type="v"/> | |
</method> | |
<method name="Set"> | |
<arg direction="in" type="s"/> | |
<arg direction="in" type="s"/> | |
<arg direction="in" type="v"/> | |
</method> | |
<method name="GetAll"> | |
<arg direction="in" type="s"/> | |
<arg direction="out" type="a{sv}"/> | |
</method> | |
<signal name="PropertiesChanged"> | |
<arg type="s"/> | |
<arg type="a{sv}"/> | |
<arg type="as"/> | |
</signal> | |
</interface> | |
<interface name="org.mpris.MediaPlayer2"> | |
<property name="Identity" type="s" access="read" /> | |
<property name="DesktopEntry" type="s" access="read" /> | |
<property name="SupportedMimeTypes" type="as" access="read" /> | |
<property name="SupportedUriSchemes" type="as" access="read" /> | |
<property name="HasTrackList" type="b" access="read" /> | |
<property name="CanQuit" type="b" access="read" /> | |
<property name="CanSetFullscreen" type="b" access="read" /> | |
<property name="Fullscreen" type="b" access="readwrite" /> | |
<property name="CanRaise" type="b" access="read" /> | |
<method name="Quit" /> | |
<method name="Raise" /> | |
</interface> | |
<interface name="org.mpris.MediaPlayer2.Player"> | |
<property name="Metadata" type="a{sv}" access="read" /> | |
<property name="PlaybackStatus" type="s" access="read" /> | |
<property name="LoopStatus" type="s" access="readwrite" /> | |
<property name="Volume" type="d" access="readwrite" /> | |
<property name="Shuffle" type="d" access="readwrite" /> | |
<property name="Position" type="i" access="read" /> | |
<property name="Rate" type="d" access="readwrite" /> | |
<property name="MinimumRate" type="d" access="readwrite" /> | |
<property name="MaximumRate" type="d" access="readwrite" /> | |
<property name="CanControl" type="b" access="read" /> | |
<property name="CanPlay" type="b" access="read" /> | |
<property name="CanPause" type="b" access="read" /> | |
<property name="CanSeek" type="b" access="read" /> | |
<method name="Previous" /> | |
<method name="Next" /> | |
<method name="Stop" /> | |
<method name="Play" /> | |
<method name="Pause" /> | |
<method name="PlayPause" /> | |
<method name="Seek"> | |
<arg type="x" direction="in" /> | |
</method> <method name="OpenUri"> | |
<arg type="s" direction="in" /> | |
</method> | |
<method name="SetPosition"> | |
<arg type="o" direction="in" /> | |
<arg type="x" direction="in" /> | |
</method> | |
</interface> | |
<interface name="org.mpris.MediaPlayer2.TrackList"> | |
<property name="Tracks" type="ao" access="read" /> | |
<property name="CanEditTracks" type="b" access="read" /> | |
<method name="GetTracksMetadata"> | |
<arg type="ao" direction="in" /> | |
<arg type="aa{sv}" direction="out" /> | |
</method> | |
<method name="AddTrack"> | |
<arg type="s" direction="in" /> | |
<arg type="o" direction="in" /> | |
<arg type="b" direction="in" /> | |
</method> | |
<method name="RemoveTrack"> | |
<arg type="o" direction="in" /> | |
</method> | |
<method name="GoTo"> | |
<arg type="o" direction="in" /> | |
</method> | |
<signal name="TrackListReplaced"> | |
<arg type="ao" /> | |
<arg type="o" /> | |
</signal> | |
<signal name="TrackAdded"> | |
<arg type="a{sv}" /> | |
<arg type="o" /> | |
</signal> | |
<signal name="TrackRemoved"> | |
<arg type="o" /> | |
</signal> | |
<signal name="TrackMetadataChanged"> | |
<arg type="o" /> | |
<arg type="a{sv}" /> | |
</signal> | |
</interface> | |
</node> | |
]] | |
local node_info = Gio.DBusNodeInfo.new_for_xml(xml) | |
function getPid() | |
require "io" | |
local f=io.open("/proc/self/stat") | |
local pid=f:read("*n") | |
f:close() | |
return pid | |
end | |
function handle_call(conn, sender, obj_path, intf_name, meth_name, params, invoc) | |
if obj_path == MPRIS2_OBJPATH then | |
if intf_name == "org.mpris.MediaPlayer2" then | |
if meth_name == "Quit" then | |
mp.command("quit") | |
end | |
elseif intf_name == "org.mpris.MediaPlayer2.Player" then | |
if meth_name == "Play" then | |
mp.set_property_native("pause", false) | |
invoc:return_value(nil) | |
return | |
elseif meth_name == "Pause" then | |
mp.set_property_native("pause", true) | |
invoc:return_value(nil) | |
return | |
elseif meth_name == "Stop" then | |
mp.command("stop") | |
invoc:return_value(nil) | |
return | |
elseif meth_name == "Previous" then | |
mp.command("playlist-prev") | |
invoc:return_value(nil) | |
return | |
elseif meth_name == "Next" then | |
mp.command("playlist-next") | |
invoc:return_value(nil) | |
return | |
elseif meth_name == "Seek" then | |
if params and params:get_type_string() == "(x)" then | |
local us = params.value[1] | |
mp.commandv("seek", string.format("%d", us / 1000000), "relative") | |
invoc:return_value(nil) | |
return | |
end | |
elseif meth_name == "PlayPause" then | |
local pause = mp.get_property_native("pause") | |
mp.set_property_native("pause", not pause) | |
invoc:return_value(nil) | |
return | |
end | |
elseif intf_name == "org.freedesktop.DBus.Properties" then | |
if meth_name == "Get" then | |
if params and params:get_type_string() == "(ss)" then | |
local p= params.value | |
print("[NYI] Property Get:", p[1], p[2]) | |
-- TODO implement getter | |
-- invoc:return_value(TODO) | |
-- return | |
end | |
elseif meth_name == "Set" then | |
if params and params:get_type_string() == "(ssv)" then | |
local p= params.value | |
print("[NYI] Property Set:", p[1], p[2]) | |
-- TODO implement setter | |
-- invoc:return_value(nil) | |
-- return | |
end | |
end | |
end | |
end | |
invoc:return_dbus_error("org.freedesktop.DBus.Error.UnknownMethod", "No such method '" .. meth_name .. "' in interface '" .. intf_name .. "'") | |
end | |
local _m = {} | |
local last_timeout = nil; | |
_m.dispatch_events = function() | |
mp.dispatch_events() | |
local time = mp.get_next_timeout(); | |
if time then | |
if time == last_timeout then return true end | |
GLib.timeout_add(time, _m.dispatch_timeout) | |
end | |
last_timeout = time | |
return false | |
end | |
_m.dispatch = function(fd) | |
local _ = _m.dispatch | |
local st = _m.ioc:read_line_string(_m.buf, 0) | |
_m.dispatch_events() | |
if not mp.keep_running then return false end | |
return true | |
end | |
function quit() | |
Gio.bus_unown_name(_m.name_id) | |
_m.mainloop:quit() | |
end | |
_m.mainloop = GLib.MainLoop() | |
_m.node_info = node_info | |
_m.fd = mp.get_wakeup_pipe() | |
_m.ioc = GLib.IOChannel.unix_new(_m.fd) | |
_m.buf = GLib.String() | |
_m.source = GLib.unix_fd_add_full(0, | |
_m.fd, | |
GLib.IOCondition{"IN", "HUP", "ERR", "OUT"}, | |
_m.dispatch, nil) | |
_G.mp_event_loop = function() | |
mp.register_event("shutdown", quit) | |
_m.mainloop:run() | |
end | |
BUSNAME = string.format("org.mpris.MediaPlayer2.mpv.pid%s", getPid()) | |
_m.name_id = Gio.bus_own_name(Gio.BusType.SESSION, BUSNAME, Gio.BusNameOwnerFlags.NONE, | |
GObject.Closure(function(conn, name) | |
-- print("Got Bus") | |
for i = 1, #node_info.interfaces do | |
conn:register_object( | |
MPRIS2_OBJPATH, | |
node_info.interfaces[i], | |
GObject.Closure(handle_call), | |
GObject.Closure(function() print "get_property_closure" end), | |
GObject.Closure(function() print "set_property_closure" end) | |
) | |
end | |
end), | |
GObject.Closure(function() | |
-- print("Got Name") | |
end), | |
GObject.Closure(function() | |
-- print("Name Lost") | |
end) | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PKGBUILD for lua52-lgi | |
# Maintainer: NONE | |
# lua-lgi Maintainer: speps <speps at aur dot archlinux dot org> | |
# lua-lgi Maintainer: Sébastien Luttringer | |
_pkgbase=lgi | |
pkgname=lua52-lgi | |
pkgver=0.9.1 | |
pkgrel=1 | |
pkgdesc='Lua 5.2 bindings for gnome/gobject using gobject-introspection library' | |
arch=(i686 x86_64) | |
url='https://github.com/pavouk/lgi' | |
license=('custom:MIT') | |
depends=('glibc' 'glib2' 'libffi' 'lua52' 'gobject-introspection-runtime') | |
makedepends=('gobject-introspection') | |
replaces=('lgi') | |
conflicts=('lgi') | |
source=("$_pkgbase-$pkgver.tar.gz::https://github.com/pavouk/$_pkgbase/archive/$pkgver.tar.gz") | |
md5sums=('0c85f177e4b8192bd849b4e508c8bdf0') | |
build() { | |
cd $_pkgbase-$pkgver | |
make PREFIX=/usr LUA_VERSION=5.2 LUA_CFLAGS="$(pkg-config --cflags lua52) -O2" | |
} | |
package() { | |
cd $_pkgbase-$pkgver | |
make \ | |
LUA_LIBDIR=/usr/lib/lua/5.2 \ | |
LUA_SHAREDIR=/usr/share/lua/5.2 \ | |
DESTDIR="$pkgdir/" install | |
# dump typelib tool | |
install -Dm755 tools/dump-typelib.lua \ | |
"$pkgdir/usr/bin/dump-typelib-lua5.2" | |
# docs | |
install -d "$pkgdir/usr/share/doc/$pkgname" | |
install -Dm644 docs/* \ | |
"$pkgdir/usr/share/doc/$pkgname" | |
# samples | |
install -d "$pkgdir/usr/share/$pkgname/samples/gtk-demo" | |
install -Dm644 samples/*.lua \ | |
"$pkgdir/usr/share/$pkgname/samples" | |
install -Dm644 samples/gtk-demo/* \ | |
"$pkgdir/usr/share/$pkgname/samples/gtk-demo" | |
# license | |
install -Dm644 LICENSE \ | |
"$pkgdir/usr/share/licenses/$pkgname/LICENSE" | |
} | |
# vim:set ts=2 sw=2 et: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This plugin provides a working mpris2 interface, but the interface doesn't call itself "mpv" or use mpv's icon.