使用 DBus 监听传入的 libnotify 通知

使用 DBus 监听传入的 libnotify 通知

我正在尝试通过 espeak 过滤每条通知。但是,我似乎找不到从 python 脚本中获取通知正文的方法,甚至不知道要监听哪个 signal_name。

bus.add_signal_receiver(espeak,
                    dbus_interface="org.freedesktop.Notifications",
                    signal_name="??")

尝试用谷歌搜索这个问题似乎只会产生涉及创建新通知的结果,所以我现在完全迷失了。

有人能帮助我吗?

简而言之,我想要的是使用 python 监听传入的通知,并获取通知的“body”属性。

答案1

为了保持最新状态:从 dbus 1.5 开始,添加匹配字符串时需要一个额外的参数,以bus.add_match_string_non_blocking确保我们收到所有内容。

最终的代码如下:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def notifications(bus, message):
    print [arg for arg in message.get_args_list()]

DBusGMainLoop(set_as_default=True)

bus = dbus.SessionBus()
bus.add_match_string_non_blocking("eavesdrop=true, interface='org.freedesktop.Notifications', member='Notify'")
bus.add_message_filter(notifications)

mainloop = glib.MainLoop()
mainloop.run()

答案2

你说的通知是指某些软件发送的“OSD 气泡”,比如音量调节、IM 聊天等?你想创建一个 Python 程序来捕获这些吗?

好吧,Ask Ubuntu 不是程序员的 QA,软件开发有点超出范围,但这里有一小段我确实捕获通知气泡的代码:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def notifications(bus, message):
    if message.get_member() == "Notify":
        print [arg for arg in message.get_args_list()]

DBusGMainLoop(set_as_default=True)

bus = dbus.SessionBus()
bus.add_match_string_non_blocking("interface='org.freedesktop.Notifications'")
bus.add_message_filter(notifications)

mainloop = glib.MainLoop()
mainloop.run()

让其在终端中运行,然后打开另一个终端窗口并测试它:

notify-send --icon=/usr/share/pixmaps/debian-logo.png "My Title" "Some text body"

程序将输出以下内容:

[dbus.String(u'notify-send'), dbus.UInt32(0L), dbus.String(u'/usr/share/pixmaps/debian-logo.png'), dbus.String(u'My Title'), dbus.String(u'Some text body'),...

你可能已经猜到了,message.get_args_list()[0][2] 是发件人,[3] 是摘要,[4] 是正文。

有关其他字段的含义,请查看官方规范文档

答案3

我很难让其他示例真正发挥作用,但最终我还是成功了。这是一个可行的示例:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def print_notification(bus, message):
  keys = ["app_name", "replaces_id", "app_icon", "summary",
          "body", "actions", "hints", "expire_timeout"]
  args = message.get_args_list()
  if len(args) == 8:
    notification = dict([(keys[i], args[i]) for i in range(8)])
    print notification["summary"], notification["body"]

loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_bus.add_match_string("type='method_call',interface='org.freedesktop.Notifications',member='Notify',eavesdrop=true")
session_bus.add_message_filter(print_notification)

glib.MainLoop().run()

如果你想看更详细的工作示例,我建议你看看recent_notifications 中的 Notifications.py项目。

答案4

上面的例子一开始没有起作用,所以我做了一些小改动,现在它可以完美地运行了。

import gi
from gi.repository import GLib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def print_notification(bus, message):
  keys = ["app_name", "replaces_id", "app_icon", "summary",
          "body", "actions", "hints", "expire_timeout"]
  args = message.get_args_list()
  if len(args) == 8:
    notification = dict([(keys[i], args[i]) for i in range(8)])
    print(notification["summary"], notification["body"])

loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_bus.add_match_string("type='method_call',interface='org.freedesktop.Notifications',member='Notify',eavesdrop=true")
session_bus.add_message_filter(print_notification)

GLib.MainLoop().run()

相关内容