Skip to content

Instantly share code, notes, and snippets.

@linuxgemini
Last active December 26, 2020 11:27
Show Gist options
  • Select an option

  • Save linuxgemini/f9e67e8160fe4f4802e769e4fd3b975f to your computer and use it in GitHub Desktop.

Select an option

Save linuxgemini/f9e67e8160fe4f4802e769e4fd3b975f to your computer and use it in GitHub Desktop.

Revisions

  1. linuxgemini revised this gist Dec 26, 2020. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions Webhook.py
    Original file line number Diff line number Diff line change
    @@ -128,8 +128,7 @@ def RepresentsInt(s):

    text += '\nStatus: **%s**' % status

    if (True or \
    os.environ.get("NZBPO_SENDWEBHOOK") == "Always" or \
    if (os.environ.get("NZBPO_SENDWEBHOOK") == "Always" or \
    (os.environ.get("NZBPO_SENDWEBHOOK") == "OnFailure" and not success)) and \
    not test_mode:
    # To get statistics or the post-processing log we connect to NZBGet via XML-RPC.
  2. linuxgemini created this gist Dec 26, 2020.
    227 changes: 227 additions & 0 deletions Webhook.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,227 @@
    #!/usr/bin/env python
    # Discord Webhook post-processing script for NZBGet
    #
    # Copyright (C) 2020 linuxgemini <nzbget@linuxgemini.space>
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # $Revision$ rev3a-release
    # $Date$ 2020-12-26
    #


    ################################################################################
    ### NZBGET POST-PROCESSING SCRIPT ###

    # Send Discord Webhook notification.
    #
    # This script sends Webhook notification when the job is done.
    #
    # NOTE: This script requires Python to be installed on your system.

    ################################################################################
    ### OPTIONS ###

    # When to send the message (Always, OnFailure).
    #SendWebhook=Always

    # Discord Webhook URL.
    #WebhookURL=https://discord.com/api/webhooks/111111111111111111/NO-TOKENS-HERE

    # Webhook Author Name.
    #WebhookAuthor=NZBGet

    # Webhook Author Image.
    #WebhookAuthorImage=https://i.imgur.com/43hnhwk.png

    # UserID to mention when Webhook is fired. eg. 686700097488420875
    #WebhookMentionID=

    # To check connection parameters click the button.
    #ConnectionTest@Send Test Webhook

    ### NZBGET POST-PROCESSING SCRIPT ###
    ################################################################################

    import os
    import re
    import sys
    import datetime
    import json
    try:
    from urllib import request as urllib2 # python 3
    from urllib.parse import quote
    from xmlrpc.client import ServerProxy
    except ImportError:
    import urllib2 # python 2
    from urllib2 import quote
    from xmlrpclib import ServerProxy

    # Exit codes used by NZBGet
    POSTPROCESS_SUCCESS=93
    POSTPROCESS_ERROR=94
    POSTPROCESS_NONE=95

    # Check if the script is called from nzbget 15.0 or later
    if not "NZBOP_NZBLOG" in os.environ:
    print("*** NZBGet post-processing script ***")
    print("This script is supposed to be called from nzbget (15.0 or later).")
    sys.exit(POSTPROCESS_ERROR)

    print("[DETAIL] Script successfully started")
    sys.stdout.flush()

    INT_RE = re.compile(r"^[-]?\d+$")

    required_options = ("NZBPO_WEBHOOKURL", "NZBPO_WEBHOOKAUTHOR", "NZBPO_WEBHOOKAUTHORIMAGE")
    for optname in required_options:
    if (not optname in os.environ):
    print('[ERROR] Option %s is missing in configuration file. Please check script setting' % optname[6:])
    sys.exit(POSTPROCESS_ERROR)

    # Check if the script is executed from settings page with a custom command
    command = os.environ.get("NZBCP_COMMAND")
    test_mode = command == "ConnectionTest"
    if command != None and not test_mode:
    print("[ERROR] Invalid command " + command)
    sys.exit(POSTPROCESS_ERROR)

    status = os.environ.get("NZBPP_STATUS") if not test_mode else "SUCCESS/ALL"
    total_status = os.environ.get("NZBPP_TOTALSTATUS") if not test_mode else "SUCCESS"

    def RepresentsInt(s):
    return INT_RE.match(str(s)) is not None

    # If any script fails the status of the item in the history is "WARNING/SCRIPT".
    # This status however is not passed to pp-scripts in the env var "NZBPP_STATUS"
    # because most scripts are independent of each other and should work even
    # if a previous script has failed. But not in the case of E-Mail script,
    # which should take the status of the previous scripts into account as well.
    if total_status == "SUCCESS" and os.environ.get("NZBPP_SCRIPTSTATUS") == "FAILURE":
    total_status = "WARNING"
    status = "WARNING/SCRIPT"

    success = total_status == "SUCCESS"

    if success and os.environ.get("NZBPO_SENDWEBHOOK") == "OnFailure" and not test_mode:
    print("[INFO] Skipping sending of message for successful download")
    sys.exit(POSTPROCESS_NONE)

    if success:
    subject = '**Success** for "**%s**"' % (os.environ.get("NZBPP_NZBNAME", "Test download"))
    text = 'Download of "**%s**" has successfully completed.' % (os.environ.get("NZBPP_NZBNAME", "Test download"))
    else:
    subject = '**Failure** for "**%s**"' % (os.environ["NZBPP_NZBNAME"])
    text = 'Download of "**%s**" has failed.' % (os.environ["NZBPP_NZBNAME"])

    text += '\nStatus: **%s**' % status

    if (True or \
    os.environ.get("NZBPO_SENDWEBHOOK") == "Always" or \
    (os.environ.get("NZBPO_SENDWEBHOOK") == "OnFailure" and not success)) and \
    not test_mode:
    # To get statistics or the post-processing log we connect to NZBGet via XML-RPC.
    # For more info visit http://nzbget.net/api
    # First we need to know connection info: host, port and password of NZBGet server.
    # NZBGet passes all configuration options to post-processing script as
    # environment variables.
    host = os.environ['NZBOP_CONTROLIP'];
    port = os.environ['NZBOP_CONTROLPORT'];
    username = os.environ['NZBOP_CONTROLUSERNAME'];
    password = os.environ['NZBOP_CONTROLPASSWORD'];

    if host == '0.0.0.0': host = '127.0.0.1'

    # Build a URL for XML-RPC requests
    rpcUrl = 'http://%s:%s@%s:%s/xmlrpc' % (quote(username), quote(password), host, port);

    # Create remote server object
    server = ServerProxy(rpcUrl)

    if not test_mode:
    # Find correct nzb in method listgroups
    groups = server.listgroups(0)
    nzbID = int(os.environ["NZBPP_NZBID"])
    for nzbGroup in groups:
    if nzbGroup["NZBID"] == nzbID:
    break

    text += '\n\nStatistics:';

    # add download size
    DownloadedSize = float(nzbGroup["DownloadedSizeMB"])
    unit = " MB"
    if DownloadedSize > 1024:
    DownloadedSize = DownloadedSize / 1024 # GB
    unit = ' GB'
    text += '\nDownloaded size: %.2f' % (DownloadedSize) + unit

    # add average download speed
    DownloadedSizeMB = float(nzbGroup["DownloadedSizeMB"])
    DownloadTimeSec = float(nzbGroup["DownloadTimeSec"])
    if DownloadTimeSec > 0: # check x/0 errors
    avespeed = (DownloadedSizeMB/DownloadTimeSec) # MB/s
    unit = " MB/s"
    if avespeed < 1:
    avespeed = avespeed * 1024 # KB/s
    unit = " KB/s"
    text += '\nAverage download speed: %.2f' % (avespeed) + unit

    def format_time_sec(sec):
    Hour = sec/3600
    Min = (sec - (sec/3600)*3600)/60
    Sec = (sec - (sec/3600)*3600)%60
    return '%d:%02d:%02d' % (Hour,Min,Sec)

    # add times
    text += "\nTotal time: " + format_time_sec(int(nzbGroup["DownloadTimeSec"]) + int(nzbGroup["PostTotalTimeSec"]))
    text += "\nDownload time: " + format_time_sec(int(nzbGroup["DownloadTimeSec"]))
    text += "\nVerification time: " + format_time_sec(int(nzbGroup["ParTimeSec"]) - int(nzbGroup["RepairTimeSec"]))
    text += "\nRepair time: " + format_time_sec(int(nzbGroup["RepairTimeSec"]))
    text += "\nUnpack time: " + format_time_sec(int(nzbGroup["UnpackTimeSec"]))


    print("[DETAIL] Forming Message")
    msg = '%s\n\n' % (subject)
    msg += text

    # Send webhook
    print('[DETAIL] Sending webhook')
    sys.stdout.flush()
    try:
    obje = {"content": msg}

    if os.environ["NZBPO_WEBHOOKAUTHOR"] != "":
    obje["username"] = os.environ["NZBPO_WEBHOOKAUTHOR"]

    if os.environ["NZBPO_WEBHOOKAUTHORIMAGE"] != "":
    obje["avatar_url"] = os.environ["NZBPO_WEBHOOKAUTHORIMAGE"]

    if os.environ["NZBPO_WEBHOOKMENTIONID"] != "" and RepresentsInt(os.environ["NZBPO_WEBHOOKMENTIONID"]):
    obje["content"] = 'CC: <@%s>\n\n%s' % (os.environ["NZBPO_WEBHOOKMENTIONID"], msg)

    par = json.dumps(obje).encode("utf8")

    req = urllib2.Request(os.environ["NZBPO_WEBHOOKURL"], par, {"content-type": "application/json"})
    req.add_header("user-agent", "NZBGet Discord Webhook")
    f = urllib2.urlopen(req)
    f.close()
    except Exception as err:
    print("[ERROR] %s" % err)
    sys.exit(POSTPROCESS_ERROR)

    # All OK, returning exit status 'POSTPROCESS_SUCCESS' (int <93>) to let NZBGet know
    # that our script has successfully completed.
    sys.exit(POSTPROCESS_SUCCESS)