-
Notifications
You must be signed in to change notification settings - Fork 336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get icon_data. #1090
Comments
#!/usr/bin/env python
import contextlib
import datetime
import dbus
import gi
gi.require_version("GdkPixbuf", "2.0")
from gi.repository import GdkPixbuf, GLib
from dbus.mainloop.glib import DBusGMainLoop
def unwrap(value):
# Try to trivially translate a dictionary's elements into nice string
# formatting.
if isinstance(value, dbus.ByteArray):
return "".join([str(byte) for byte in value])
if isinstance(value, (dbus.Array, list, tuple)):
return [unwrap(item) for item in value]
if isinstance(value, (dbus.Dictionary, dict)):
return dict([(unwrap(x), unwrap(y)) for x, y in value.items()])
if isinstance(value, (dbus.Signature, dbus.String)):
return str(value)
if isinstance(value, dbus.Boolean):
return bool(value)
if isinstance(
value,
(dbus.Int16, dbus.UInt16, dbus.Int32, dbus.UInt32, dbus.Int64, dbus.UInt64),
):
return int(value)
if isinstance(value, dbus.Byte):
return bytes([int(value)])
return value
def save_image_bytes(px_args):
# gets image data and saves it to file
save_path = f"/tmp/image-{datetime.datetime.now().strftime('%s')}.png"
# https://specifications.freedesktop.org/notification-spec/latest/ar01s08.html
# https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html
GdkPixbuf.Pixbuf.new_from_data(
width=px_args[0],
height=px_args[1],
has_alpha=px_args[3],
data=px_args[6],
colorspace=GdkPixbuf.Colorspace.RGB,
rowstride=px_args[2],
bits_per_sample=px_args[4],
).savev(save_path, "png")
print(len(px_args[6])) # DEBUG: The sizes are the same! Although, DUNST shows images changes.
return save_path
def message_callback(_, message):
if type(message) != dbus.lowlevel.MethodCallMessage:
return
args_list = message.get_args_list()
args_list = [unwrap(item) for item in args_list]
details = {
"appname": args_list[0],
"summary": args_list[3],
"body": args_list[4],
"urgency": args_list[6]["urgency"],
"iconpath": None,
}
if args_list[2]:
details["iconpath"] = args_list[2]
with contextlib.suppress(KeyError):
# for some reason args_list[6]["icon_data"][6] i.e. the byte data
# does not change unless I restart spotify but, the song title
# (body / summary) change gets picked up.
details["iconpath"] = save_image_bytes(args_list[6]["icon_data"])
print(details) # DEBUG
DBusGMainLoop(set_as_default=True)
rules = {
"interface": "org.freedesktop.Notifications",
"member": "Notify",
"eavesdrop": "true", # https://bugs.freedesktop.org/show_bug.cgi?id=39450
}
bus = dbus.SessionBus() # TODO: Use proxy.
# is there a better way of doing this? Like a adding some sort of signal?
# I could not figure out the bus.add_signal_receiver thing. How do I use this?
# Is this needed at all?
bus.add_match_string(",".join([f"{key}={value}" for key, value in rules.items()]))
bus.add_message_filter(message_callback)
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
loop.quit()
bus.close()
# vim:filetype=python Cooked this but the image_data never changes any idea why? same-image.mp4 |
I cannot believe I am so stupid. How am I even alive. In the above script I have verified that Following is the corrected script if someone needs it! #!/usr/bin/env python
import contextlib
import datetime
import dbus
import gi
gi.require_version("GdkPixbuf", "2.0")
from gi.repository import GdkPixbuf, GLib
from dbus.mainloop.glib import DBusGMainLoop
def unwrap(value):
# Try to trivially translate a dictionary's elements into nice string
# formatting.
if isinstance(value, dbus.ByteArray):
return "".join([str(byte) for byte in value])
if isinstance(value, (dbus.Array, list, tuple)):
return [unwrap(item) for item in value]
if isinstance(value, (dbus.Dictionary, dict)):
return dict([(unwrap(x), unwrap(y)) for x, y in value.items()])
if isinstance(value, (dbus.Signature, dbus.String)):
return str(value)
if isinstance(value, dbus.Boolean):
return bool(value)
if isinstance(
value,
(dbus.Int16, dbus.UInt16, dbus.Int32, dbus.UInt32, dbus.Int64, dbus.UInt64),
):
return int(value)
if isinstance(value, dbus.Byte):
return bytes([int(value)])
return value
def save_img_byte(px_args):
# gets image data and saves it to file
save_path = f"/tmp/image-{datetime.datetime.now().strftime('%s')}.png"
# https://specifications.freedesktop.org/notification-spec/latest/ar01s08.html
# https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html
GdkPixbuf.Pixbuf.new_from_bytes(
width=px_args[0],
height=px_args[1],
has_alpha=px_args[3],
data=GLib.Bytes(px_args[6]),
colorspace=GdkPixbuf.Colorspace.RGB,
rowstride=px_args[2],
bits_per_sample=px_args[4],
).savev(save_path, "png")
return save_path
def message_callback(_, message):
if type(message) != dbus.lowlevel.MethodCallMessage:
return
args_list = message.get_args_list()
args_list = [unwrap(item) for item in args_list]
details = {
"appname": args_list[0],
"summary": args_list[3],
"body": args_list[4],
"urgency": args_list[6]["urgency"],
"iconpath": None,
}
if args_list[2]:
details["iconpath"] = args_list[2]
with contextlib.suppress(KeyError):
# for some reason args_list[6]["icon_data"][6] i.e. the byte data
# does not change unless I restart spotify but, the song title
# (body / summary) change gets picked up.
details["iconpath"] = save_img_byte(args_list[6]["image-data"])
print(details) # DEBUG
DBusGMainLoop(set_as_default=True)
rules = {
"interface": "org.freedesktop.Notifications",
"member": "Notify",
"eavesdrop": "true", # https://bugs.freedesktop.org/show_bug.cgi?id=39450
}
bus = dbus.SessionBus()
bus.add_match_string(",".join([f"{key}={value}" for key, value in rules.items()]))
bus.add_message_filter(message_callback)
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
bus.close()
# vim:filetype=python |
Closing! |
Great that you've solved it and thanks for providing your solution! |
@dharmx I cannot believe you are so smart! So if I run this script while I receive notifs then the
Could your script be used to parse the |
The script does exactly that. You Just execute that and forget. It'll save the images to ./notify | while read -r metadata; do
# read using jq or whatever
done |
@dharmx I can't figure it out, for sure I'm the stupid one here. 😁 I do have the |
Any, notification daemon should work. Like dunst, tiramisu, naughty (AwesomeWM), etc. But yes, you would need to have any one of these installed. Here's a demo and code. output2.mp4 |
I mean I just have stock Gnome with default FreeDesktop notifications I guess. |
Issue description
How do I get the icon_data through a script. For example, Discord sends the profile picture in byte format and Spotify sends the album art in byte format. I am making a notification manager so I was wondering if getting these hints would be possible or not and if so how? Also, the
dunstctl history
part also doesn't have them. The icon data path is empty!However, upon monitoring the DBUS interface(?) I do see that the icon data is being returned. Note that the notifications itself work fine! The images do show when I am pinged from Discord. I just want the icon bytes so I can parse it in my script.
Installation info
Version: Dunst - A customizable and lightweight notification-daemon v1.8.1-60-g3bba0b0
Install type: From AUR from here
Window manager: BSPWM
Minimal dunstrc
Please, ask if you need any additional info.
The text was updated successfully, but these errors were encountered: