caronc / apprise

Apprise - Push Notifications that work with just about every platform!
https://hub.docker.com/r/caronc/apprise
BSD 2-Clause "Simplified" License
11.62k stars 406 forks source link

Custom Plugins Built Using a Decorator - @notify("myschema") #454

Closed caronc closed 2 years ago

caronc commented 2 years ago

:bulb: The Idea

This enhancement request stems from a conversation here. The thought was to leverage Python decorators to allow users to write their own basic Apprise plugins.

This would allow people to leverage the apprise to support their own edge cases.

Their code would simply look like this:

# A custom apprise service we want to trigger as foobar://
from apprise.decorators import notify

@notify('foobar')
def my_custom_apprise_service(body, title, notify_type, attach, meta, *args, **kwargs):
    """
    This function will automatically get called if/when a user launching apprise
    references the foobar:// URL (as defined by the service above)

    """
    # Always end your declaration with *args and **kwargs so that you can be forwards
    # compatible with new updates to this wrapper.

    # Utilize the body, title, and notify_type as well if you want to customize whatever it is you intend to
    # do here.

    # The meta contains the entire URL already parse for you when it was loaded
    # by someone's configuration entry.

    # Return True at the end of your function if you want to report back to Apprise that the
    # notification was sent successfully, otherwise return False.  If you return None, this is
    # interpreted as True
    return True

Presuming your custom file is placed within a directory Apprise is set to scan, it will add whatever protocol you specified to the ones supported and will execute your function whenever the protocol is matched.

# e.g.
apprise -vvv --plugin-dir=/path/to/plugins
   - b "a specified body"

:gear: TODO

Limitations and Notes:

Summary

The decorator would provide a very simple adaption and therefore would lack all of the bullet proofing, and error checking and reverse url() calls otherwise provided by the built in functions. But it's basic capability could still be incredibly useful for some.

:hammer: Breaking Feature

Nothing will break

dgtlmoon commented 2 years ago

This is excellent!

For example, my project is https://github.com/dgtlmoon/changedetection.io , which is generally used as a docker container, would be great if people could add their own custom notification services (some people need to send a specific notification to some special device/service)

I could see a whole 'un-official' apprise service notification library/github repo out there :)

caronc commented 2 years ago

Making a lot of progress here... I thought the best way to identify the decorator would be:

from apprise.decorators import notify

# Trigger on foobar://
@notify(on="foobar")
def my_custom_function_to_be_called(body, title, notify_type, *args, **kwargs):
    """
    define your function here and do whatever it is you want...
    """

The idea is now foobar:// is now a fully accessible and configurable URL for apprise now. I even worked it into the API so when you call Apprise.details(), you can see this new objects and pass them along to the end users.

I started documenting the actual pull request in much greater detail. So far it's working great. I have no test coverage at this time, but that will come soon. heading on vacation for 2 weeks, so there will be a stall in development.

I think i made it so it nicely integrates with the current setup and by default the plugin_paths (directories/files scanned to be loaded) are not initialized (so nothing is performed; Apprise behaves as it does today). So it will be an additional option dev's would have to leverage if they wanted to take advantage of it.

But i would love your feedback on the design approach taken. Any advice/thoughts/considerations?

Chris

caronc commented 2 years ago

Code merged; closing issue