Skip to content
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

Interrupt a notification using script #906

Closed
Iss-in opened this issue Sep 10, 2021 · 18 comments
Closed

Interrupt a notification using script #906

Iss-in opened this issue Sep 10, 2021 · 18 comments

Comments

@Iss-in
Copy link

Iss-in commented Sep 10, 2021

Is it possible to interrupt a notification via bash script, which isnt possible due to limited config functionality ?

like I want a app1 notification to be displayed only if app2 is running in background currently ?

@fwsmit
Copy link
Member

fwsmit commented Sep 10, 2021

No, that's not yet possible. Something # like a script that runs before the notification is shown could help.

@Iss-in
Copy link
Author

Iss-in commented Sep 10, 2021

yeah, we could just termminate the current dunst process in it, any plan of implementing it ? I could try to take a look it

@Iss-in
Copy link
Author

Iss-in commented Sep 13, 2021

nevermind, its working if you set the script in config first, and then put summary=""

@Iss-in Iss-in closed this as completed Sep 13, 2021
@fwsmit
Copy link
Member

fwsmit commented Sep 13, 2021

nevermind, its working if you set the script in config first, and then put summary=""

Does that fit your use case? I thought you wanted to dynamically change it. Of course that's possible when automatically changing the config and restarting dunst. #719 would probably help. I'll be working on that soon™

@Iss-in
Copy link
Author

Iss-in commented Sep 13, 2021

I mean, In the script I can just create another notification using the parameters. so yeah, it solved my problem

@xoores
Copy link

xoores commented Feb 24, 2022

Hi,

I'm also looking into this - I want to "implement" some DND mode where some notifications will go through, some will also make a sound etc... And I want this to be dynamic, without needing to prepare 2 configurations and swap them around etc...

The idea behind this is that I used Macos for 4 years and its notification handling was quite nice and I do miss some "system-wide" way of telling that e.g. mail application should be quiet (damn you, Thunderbird) except for mails with high priority set etc.

Basically I thought about 2 approaches:

  1. check returncode of script and just drop a notification if returns non-zero or some pre-determined code or
  2. re-parsing ENV variables used for passing arguments to the script, effectively allowing a script to do an "override"

Option no. 2 would allow for much better customization (on-the-fly priority override for something etc) but I'd need to properly sanitize the input of course.

Both of these would require for notifications to "wait" for the script (maybe it would be worth to create new option instead of script to keep backward compatibiliy? Dunno...)

Am I alone in this? I'm asking because if you might want to merge this feature, I'd spend the time to make this "nicer" - otherwise I'd just hack it in fast'n'furious style 😆

@fwsmit
Copy link
Member

fwsmit commented Feb 25, 2022

Hi @xoores,

Cool that you want to work on this. A number of other people have been requesting a do not disturb mode. There is of course dunstctl pause, but that doesn't let a single notification through. I have been thinking of a nice way to do this and I like the way mako does it:

mako supports applying style options conditionally via modes. A configuration section with a mode criteria will only be applied if the current mode matches.
makoctl(1) can be used to change the current mode.

The default mode is named "default".

For example, to hide all notifications if the mode "do-not-disturb" is enabled:

    [mode=do-not-disturb]
    invisible=1

makoctl set-mode do-not-disturb will hide all notifications, makoctl set-mode default will show them again.

This is easier to configure than making tons of scripts and it's almost as flexible. It shouldn't be too hard to implement either. We could even add an option to delay notifications, just like when dunst is pause, so you can read the missed notifications back.

Take a look at #865 as well.

Do you think this would be a good way to do it?

@xoores
Copy link

xoores commented Feb 26, 2022

Hi @fwsmit

I looked at that issue 🙂

yeah, pause will just stop all the notifications. I looked at Mako (don't have Wayland so didn't know about that one) and it seems that it can apply some property to all notifications based on "mode". Meaning it is not dynamic in a way that would allow you to say e.g. "don't show notifications from mail unless they are important" etc. Dunst has similar logic but "inverted" to this by matching on sections but it basically does the same. I think that Dunst could replicate this by letting you enable/disable sections at runtime.
I think that modes as in Mako could be nice, but I would say that they are slightly for different use-case - for example light/dark themes etc as you could nicely override color scheme based on mode etc. It would not enable you to for example display only notifications based on external conditions or "pause" them if (not)matched to something.
The closest thing for that use-case would be if invisible could be set per section, not globally but it does not seem to be the case.

I think that allowing scripts to alter the notifications would open up almost limitless possibilities. Honestly I would suggest to keep the script as it is now so it is 1) backwards compatible and 2) Dunst does not have to wait for script to finish. I'd suggest to add some other option, for example something like handler. That one could be fired after receiving event (either honoring paused or not) and would be blocking (timeout should be in place). 🙂

Of course it is also possible that I completely misunderstood Mako's manpage and it is more powerful that it seems now 🙂 If that is the case, please correct me. If I understood Mako correctly, what would you say to the handler approach to allow really dynamic notification handling?

@fwsmit
Copy link
Member

fwsmit commented Feb 26, 2022

Hi @fwsmit

I looked at that issue slightly_smiling_face

yeah, pause will just stop all the notifications. I looked at Mako (don't have Wayland so didn't know about that one) and it seems that it can apply some property to all notifications based on "mode". Meaning it is not dynamic in a way that would allow you to say e.g. "don't show notifications from mail unless they are important" etc. Dunst has similar logic but "inverted" to this by matching on sections but it basically does the same.

Depending on how you know if an email is important it's possible. First, there is skip_display, that will let you skip a certain notification. Second, you can match the notification based on a number of factors (the filtering rules). If you are able to match this notification with the filtering rules, it's possible. The mode would just add another filtering rule that would get a dynamic value that can be set with dunstctl. If you want to look at the rules, take a look at dunst's man page (dunst(5)).

How would you know if an email is important? Could you for example match it with regex based on the summary?

I think that Dunst could replicate this by letting you enable/disable sections at runtime. I think that modes as in Mako could be nice, but I would say that they are slightly for different use-case - for example light/dark themes etc as you could nicely override color scheme based on mode etc. It would not enable you to for example display only notifications based on external conditions or "pause" them if (not)matched to something.

With the modes as they work in mako, you could set a "do no disturb mode", but it would not be suited for do not disturb for individual applications, each of them being individually toggle-able. You could make it so that a new mode doesn't replace the old one, e.g. multiple modes can be active, but that would be more complicated to implement and use.

You'd be delighted to know that you can toggle rules with dunstctl rule NAME [toggle|enable|disable]. Even though you could probably do everything a mode can with that, a mode would be a bit more easy to use from a user perspective.

The closest thing for that use-case would be if invisible could be set per section, not globally but it does not seem to be the case.

As I said above, you can set that per section (as a filtering rule). Why did you think it was not? Could the documentation about it be improved?

I think that allowing scripts to alter the notifications would open up almost limitless possibilities. Honestly I would suggest to keep the script as it is now so it is 1) backwards compatible and 2) Dunst does not have to wait for script to finish. I'd suggest to add some other option, for example something like handler. That one could be fired after receiving event (either honoring paused or not) and would be blocking (timeout should be in place). slightly_smiling_face
Of course it is also possible that I completely misunderstood Mako's manpage and it is more powerful that it seems now slightly_smiling_face If that is the case, please correct me. If I understood Mako correctly, what would you say to the handler approach to allow really dynamic notification handling?

There is a proposal that relates to running scripts before a notification #879. I agree this is the most flexible solution, but it's not the easiest to use. Also, there is currently no good way for scripts to edit a notification's properties. So if your use case is covered by the modes, then I would suggest that.

@xoores
Copy link

xoores commented May 3, 2022

Sorry for the delay, had quite a lot of things that I had to deal with 🙂

Important email could be determined by some "VIP" people for example - basically regexing notification. But the thing is not to only run with simple filtering because I ran into more painpoints in regards to notifications:

  • Most of the notifications I tend to see are suboptimal. Full of clutter and the important bits are shoved into body instead of title and there is usually no way to alter those. Example: I don't need summary "Direct message" and everything else crammed into body. I'd like to move author from body to the summary etc. Similar problem is with Evolution notifications.
  • Similar thing goes for actions, I quite miss some kind of "script" action because in i3 i'd like to be able to click on notification with the result that I'd be switched to the corresponding workspace. Url invokation cannot do that unfortunately, the only result is that urgency flag of the target window is raised.

I don't think that dunst can do that with rules/modes alone. And it would also be untrivial to try to invent a way to put it directly into the config. Hence the proposition for scripting which could be used by someone who really wants to dig deep 🙂 Regarding the way to change values: I would try to go with editting ENV variables passed to the script with some rudimentary checks around that. Should be good and easy enough for proof-of-concept, we can also ignore invalid changes (use the original value instead). Also it would be easily expandable in the future.

I missed that you can toggle rules, I love it! Is there a way to check whether rule is enabled or disabled?

@fwsmit
Copy link
Member

fwsmit commented May 6, 2022

I missed that you can toggle rules, I love it! Is there a way to check whether rule is enabled or disabled?

Not yet. You can implement it if you want :)

@fwsmit
Copy link
Member

fwsmit commented May 6, 2022

Yeah I get that you cannot do everything with the rule functionality of dunst. For some thinks you really need a script. There exists already an issue about that: #899

@xoores
Copy link

xoores commented May 6, 2022

I have proof-of-concept of editting notifications from shell script 😁 I will add this check also, but first I will finish up this so you can take a look at it & discuss potential direction of it. For now I went with MMAP as it is the easiest way but in the end I'd go for pthreads etc. 🙂

@fwsmit
Copy link
Member

fwsmit commented May 6, 2022

Cool, I'll take a look when you post something.

@xoores
Copy link

xoores commented May 6, 2022

I'll clean it up a little bit and push it to my branch. For now I crammed everything in notification.c but final solution (mergeable) would have to be in its own sourcefile (if we would want to keep 100% backwards compatibility by leaving script as is and adding different option for this) and written using pthreads (as thread shares memory and therefore it is possible to alter data for the parent process).

If you'd decide to just change the script to be blocking, I could leave it in there - I basically added bool blocking to notification_run_script for now.

As for now it looks something like this:

Script:

#!/bin/bash

# Simulate some heavy work that takes time
sleep .3

export DUNST_FORMAT="<i>%s</i>\n%b"
export DUNST_TIMEOUT=1000

Result in dunst:

INFO: Found icon at /usr/share/icons/Adwaita/32x32/legacy/dialog-information.png
INFO: Notification  [ID=4  TIMEOUT=10s  URGENCY=NORMAL  TRANSIENT=N  FULLSCREEN=show]
INFO: {
INFO: 	appname: 'notify-send'
INFO: 	summary: 'test'
INFO: 	format: <b>%s</b>\n%b
INFO: 	formatted: '<b>test</b>'
INFO: 	icon: 'dialog-information'
INFO: 	raw_icon set: N
INFO: 	fg: #ffffff
INFO: 	bg: #2885A7
INFO: 	highlight: #1745d1
INFO: 	frame: #ffffff
INFO: 	scripts: {
INFO: 		'/scripts/dunster.sh'
INFO: 	}
INFO: }
INFO: Firing blocking script: /scripts/dunster.sh
INFO: Script '/scripts/dunster.sh' returned 0 in 308ms
INFO: Script overrides FORMAT: '<b>%s</b>\n%b' -> '<i>%s</i>\n%b'
INFO: Script overrides TIMEOUT: 10000 -> 1000
INFO: Script made some changes, will re-format the message
INFO: Notification  [ID=4  TIMEOUT=1s  URGENCY=NORMAL  TRANSIENT=N  FULLSCREEN=show]
INFO: {
INFO: 	appname: 'notify-send'
INFO: 	summary: 'test'
INFO: 	format: <i>%s</i>\n%b
INFO: 	formatted: '<i>test</i>'
INFO: 	icon: 'dialog-information'
INFO: 	raw_icon set: N
INFO: 	fg: #ffffff
INFO: 	bg: #2885A7
INFO: 	highlight: #1745d1
INFO: 	frame: #ffffff
INFO: 	scripts: {
INFO: 		'/scripts/dunster.sh'
INFO: 	}
INFO: }

(I also updated that notification_print() so it uses LOG_* and less lines overall because too many lines = log just scrolls at light speed and I cannot really read it 😆)

@xoores
Copy link

xoores commented May 7, 2022

Okay, got first version here: https://github.com/xoores/dunst/tree/feature-advanced-scripting

This version can override several fields: urgency, icon_path, stack_tags, category, format, body, summary, progress, transient and timeout. It uses some bash incantations to acheve this, mmap to move data around and some pointer-based parsing.

I tried to document as much as possible to make it easier to understand what I was going for.

If script returns anything else than 0, the notification is thrown away. If one script returns non-zero status, no other scripts are run. This is for debate, someone might want to use this as e.g. way to push notifications to Slack or something and it this scenario it would be of course bad.

If script fails to run or if script outputs too much, it will be ignored (warn will be printed). Meaning no changes will be made to the notification - playing it safe here 🙂

I run this version and I use it to change some fields like this:

#!/bin/bash

if [[ "${DUNST_BODY}" == *mattermost.xxx.yy* ]]; then
       	DUNST_BODY="$(echo "${DUNST_BODY}" | sed -e 's|<a[^@]*||g' -e 's|\(@[^:]*:\)|<b>\1</b>|g' | xargs)"
fi

Notes:

  • It might be nice to specify some kind of timeout for the script since it is blocking
  • script arguments should be abolished as there was no escaping etc (unpredictable)
  • Some methods should be moved around - I wanted to edit only the files I had to (easier merging)
  • Still have to finish fields such as colors as well 🤷

I also changed the following:

  • Changed notification_print so it uses LOG_* in more compact way
  • Urgency-based colors are applied by default when urgency is changed through script or rule. If something changes color, urgency-based defaults will not be applied automatically.

Questions:

  • How do you want to proceed? Shall I create merge request & we can move all the discussion there or shall I continue to work on this and merge it later?
  • Should I continue altering script or should I create some other option for this so it is 100% backwards compatible?

@fwsmit
Copy link
Member

fwsmit commented May 8, 2022

Thank you for posting your branch. I think it's best if you made a pull request for it, so I can more easily comment on it. I do have some initial feedback. Please keep unrelated changes out as much as possible, since I do have some comments on them, which slow down the merging on the actual changes you wanted to make. If you want you can make a separate issue or PR for that.
As for modifying the script key, my idea for implementing this idea was #879 where you can choose when a script should be run using the event key. Let me know if that's something you want to work on.

@xoores
Copy link

xoores commented May 8, 2022

Created 🙂

Yeah, the #879 is also something I want to tackle as I'd really like to be able to switch worskpaces 😁

Also don't worry about unrelated changes, we can definitely discuss them or outright reject them - some of these were done for ease of debugging and for me to understand the code quicker 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants