[PP-Script] NotifyPlex - Library Update and GUI Notification

Share your scripts or request scripts with specific features.
Forum rules
Please keep the forum clean - one topic per script. Questions not related to a specific script should be posted in Support forum.
mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

[PP-Script] NotifyPlex - Library Update and GUI Notification

Post by mannibis » 17 Aug 2014, 20:37

The PP-Script will call a targeted Plex refresh/update upon successful download and send a GUI Notification to Plex Home Theater.
If snatched via a NewzNab+ indexer, the script can use Direct NZB headers to display the ProperName and EpisodeName in the notification. This is now a new option called "dHeaders". If dHeaders is set to "No" or the indexer does not support DNZB Headers, the full NZB name will be used in the notification.

Library Refresh Mode has now been implemented

Users no longer have to enter in section numbers or copy the script to refresh their TV shows and Movies separately. Library Refresh Mode is a new option that allows the user to choose how they want to script to refresh their library. 'Auto' mode will automatically refresh TV Shows and Movies sections. The script will detect the NZBGet category and also auto-detect the Plex sections by polling the Plex Server's API to figure out what sections are for TV Shows and what sections are for Movies. The plexSections setting has been changed to customPlexSections, if the user would like to scan a section other than TV Shows or Movies. The Custom sections will only be scanned if the Library Refresh Mode is set to Custom or Both.

New settings are movieCat and tvCat. You will have to specify which NZBGet category(s) that you created are intended for movies, and which ones are intended for TV Shows

Sending a GUI Notification to Plex Home Theater client is supported by specifying the IP(s) where PHT is installed. Sending GUI Notifications to multiple clients is now supported.

The script has also been updated to support Plex Home. It will now authenticate with Plex.tv first using HTTP Basic Auth, which is now required for all API commands/methods if Plex Home is enabled. Note that you will need to add your username and password to the NotifyPlex settings (required).

Any feedback or feature requests are welcome.

Requirements: NZBGet v13+ and Python 2.x
  • Installation Instructions
  • Download NotifyPlex.zip and extract NotifyPlex folder into your NZBGet Post-Processing Scripts Directory
  • If using VideoSort or other Sort/Rename Scripts, run NotifyPlex after those scripts have sorted/renamed your files.
  • Configure Options in WebUI, Save Changes, Reload NZBGet
  • Any duplicate scripts (from previous versions) can be deleted. Only one NotifyPlex.py is needed for Movie/TV show/Custom section(s)

Code: Select all


#!/usr/bin/env python2
#
##############################################################################
### NZBGET POST-PROCESSING SCRIPT                                          ###

# Post-Process to Update Plex Library and Notify PHT.
#
# This script sends a Targeted Library Update URL to your Plex Media Server and a GUI Notification to Plex Home Theater.
# Auto-Detection of NZBGet Category and Plex Sections is now supported. 
#
# Copyright (C) 2014 mannibis
# Version 2.1
#
#
# NOTE: This script requires Python 2.x to be installed on your system.

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

## General

# Refresh Plex Library (yes,no).
#
# Activate if you want NotifyPlex to Refresh your Plex Library
#refreshLibrary=yes

# Send GUI Notification to Plex Home Theater (yes,no).
#
# Activate if you want NotifyPlex to Send a GUI Notification to Plex Home Theater
#guiShow=yes

# Use Direct NZB Proper Name for Notification (yes,no).
#
# Activate if you want to use the DNZB Header ProperName for the title of the Media if Available
#dHeaders=yes

## Plex Media Server

# Plex Media Server Settings.
#
# Host IP of your Plex Media Server including Port (Only 1 Server is Supported)
#plexIP=192.168.1.XXX:32400

# Plex.tv Username [Required]
#plexUser=
# Plex.tv Password [Required]
#plexPass=

# Library Refresh Mode (Auto,Custom,Both).
#
# Select Refresh Mode: Auto will automatically detect your NZBGet Category and Refresh the Appropriate Sections, Custom will only refresh the Sections you input into the Custom Sections setting below, Both will Auto-detect and Refresh the Custom Sections
#refreshMode=Auto

# NZBGet Movies Category/Categories [Required for Auto Mode].
#
# List the name(s) of your NZBGet categories (CategoryX.Name) that correspond to Movies (Comma Separated)
#moviesCat=movies

# NZBGet TV Category/Categories [Required for Auto Mode].
#
# List the name(s) of your NZBGet categories (CategoryX.Name) that correspond to TV Shows (Comma Separated)
#tvCat=tv

# Custom Plex Section(s) you would like to Update [Optional].
#
# Section Number(s) Corresponding to your Plex Library (Comma Seperated). These sections will only refreshed if Library Refesh Mode is set to Custom or Both
#customPlexSection=

## Plex Home Theater

# Plex Home Theater Settings [Optional].
#
# Host IP(s) of your Plex Home Theater Client(s) (Comma Separated)
#clientsIP=192.168.1.XXX

# Use Silent Failure Mode (yes,no).
#
# Activate if you want NZBGet to report a SUCCESS status regardless of Errors, in cases where PMS is offline.
#silentFailure=no

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

import os
import sys
import StringIO
import requests
import json
import xml.etree.cElementTree as ET
from requests.auth import HTTPBasicAuth

POSTPROCESS_SUCCESS=93
POSTPROCESS_ERROR=94
POSTPROCESS_NONE=95

if not 'NZBPP_STATUS' in os.environ:
        print('*** NZBGet post-processing script ***')
        print('This script is supposed to be called from NZBGet v13.0 or later.')
        sys.exit(POSTPROCESS_ERROR)

required_options = ('NZBPO_SILENTFAILURE','NZBPO_MOVIESCAT','NZBPO_TVCAT','NZBPO_REFRESHMODE','NZBPO_REFRESHLIBRARY','NZBPO_DHEADERS','NZBPO_GUISHOW','NZBPO_PLEXUSER','NZBPO_PLEXPASS')
for optname in required_options:
	if (not optname in os.environ):
		print('[ERROR] NOTIFYPLEX: Option %s is missing in configuration file. Please check script settings' % optname[6:])
		sys.exit(POSTPROCESS_ERROR)

#Check to see if download was successful
ppStatus=os.environ['NZBPP_STATUS']=='SUCCESS/ALL'

dnzboptions = ('NZBPR__DNZB_PROPERNAME', 'NZBPR__DNZB_EPISODENAME', 'NZBPR__DNZB_MOVIEYEAR')
if os.environ.has_key(dnzboptions[0]):
	properName=os.environ[dnzboptions[0]]
else:
	properName = ''
if os.environ.has_key(dnzboptions[1]):
	properEP=os.environ[dnzboptions[1]]
else:
	properEP = ''
if os.environ.has_key(dnzboptions[2]):
	properYear=os.environ[dnzboptions[2]]
else:
	properYear = ''

nzbName=os.environ['NZBPP_NZBNAME']
nzbCat=os.environ['NZBPP_CATEGORY']
guiShow=os.environ['NZBPO_GUISHOW']=='yes'
plexUsername=os.environ['NZBPO_PLEXUSER']
plexPassword=os.environ['NZBPO_PLEXPASS']
refreshLibrary=os.environ['NZBPO_REFRESHLIBRARY']=='yes'
refreshMode=os.environ['NZBPO_REFRESHMODE']
silentMode=os.environ['NZBPO_SILENTFAILURE']=='yes'


def getAuthToken(plexUser,plexPass):

	urlAuth = 'https://my.plexapp.com/users/sign_in.xml'
	headers = {
			'X-Plex-Platform':'NZBGet',
			'X-Plex-Platform-Version':'14.0',
			'X-Plex-Provides':'controller',
			'X-Plex-Product':'NotifyPlex',
			'X-Plex-Version':"2.0",
			'X-Plex-Device':'NZBGet',
			'X-Plex-Client-Identifier':'12286'
	}
	try:
		token = None
		auth = requests.post(urlAuth, headers=headers, auth=HTTPBasicAuth(plexUser,plexPass))
		strResponse = StringIO.StringIO(auth.content)
		tree = ET.parse(strResponse)
		for elem in tree.getiterator():
			if (elem.tag=='authentication-token'):
				token = elem.text.strip()
				print ('[INFO] NOTIFYPLEX: Plex.tv Authentication Successful')
				return token
	except requests.Timeout or requests.ConnectionError or requests.HTTPError:
		if silentMode:
			print ('[WARNING] NOTIFYPLEX: There was an Error Authenticating. Silent Failure Mode Activated')
			sys.exit(POSTPROCESS_SUCCESS)
		else:	
			print ('[ERROR] NOTIFYPLEX: Error Authenticating using Plex.tv')
			sys.exit(POSTPROCESS_ERROR)
	if (token == None):
		if silentMode:
			print ('[WARNING] NOTIFYPLEX: There was an Error Authenticating. Silent Failure Mode Activated')
			sys.exit(POSTPROCESS_SUCCESS)
		else:	
			print ('[ERROR] NOTIFYPLEX: Error Authenticating using Plex.tv')
			sys.exit(POSTPROCESS_ERROR)

def refreshAuto(movieCATs, tvCATs, plexIP):

	movieCATSplit = movieCATs.split(',')
	tvCATSplit = tvCATs.split(',')

	params = {
		'X-Plex-Token':getAuthToken(plexUsername,plexPassword)
	}

	url = 'http://%s/library/sections' % (plexIP)
	try:
		secXML = requests.get(url,params=params,verify=False, timeout=10)
	except requests.Timeout or requests.ConnectionError or requests.HTTPError:
		if silentMode:
			print ('[WARNING] NOTIFYPLEX: Error Auto-Detecting Plex Sections. Silent Failure Mode Activated')
			sys.exit(POSTPROCESS_SUCCESS)
		else:
			print ('[ERROR] NOTIFYPLEX: Error Auto-Detecting Plex Sections. Check Network Connection and Plex Server IP, Port')
			sys.exit(POSTPROCESS_ERROR)

	strResponse = StringIO.StringIO(secXML.content)
	tree = ET.parse(strResponse)
	movieSections = []
	tvSections = []
	for elem in tree.getiterator('Directory'):
		if (elem.attrib['type'] == 'show'):
			tvSections.append(elem.attrib['key'])
		elif (elem.attrib['type'] == 'movie'):
			movieSections.append(elem.attrib['key'])

	for tCat in tvCATSplit:
		if (nzbCat == tCat):
			for tSection in tvSections:
				url = 'http://%s/library/sections/%s/refresh' % (plexIP, tSection)
				try:
					r = requests.get(url,params=params,verify=False, timeout=10)
				except requests.Timeout or requests.ConnectionError or requests.HTTPError:
					if silentMode:
						print ('[WARNING] NOTIFYPLEX: Error Updating Section %s. Silent Failure Mode Activated' % tSection)
						sys.exit(POSTPROCESS_SUCCESS)
					else:
						print ('[ERROR] NOTIFYPLEX: Error Opening URL. Check Network Connection and Plex Server IP, Port, and Section Numbers')
						sys.exit(POSTPROCESS_ERROR)
				print ('[INFO] NOTIFYPLEX: Targeted PLEX Update for Section %s Complete' % tSection)

	for mCat in movieCATSplit:
		if (nzbCat == mCat):
			for mSection in movieSections:
				url = 'http://%s/library/sections/%s/refresh' % (plexIP, mSection)
				try:
					r = requests.get(url,params=params,verify=False, timeout=10)
				except requests.Timeout or requests.ConnectionError or requests.HTTPError:
					if silentMode:
						print ('[WARNING] NOTIFYPLEX: Error Updating Section %s. Silent Failure Mode Activated' % mSection)
						sys.exit(POSTPROCESS_SUCCESS)
					else:
						print ('[ERROR] NOTIFYPLEX: Error Opening URL. Check Network Connection and Plex Server IP, Port, and Section Numbers')
						sys.exit(POSTPROCESS_ERROR)
				print ('[INFO] NOTIFYPLEX: Targeted PLEX Update for Section %s Complete' % mSection)


def refreshCustomSections(rawPlexSections,plexIP):

	plexSections=rawPlexSections.replace(' ','')
	plexSectionsSplit=plexSections.split(',')

	params = {
		'X-Plex-Token':getAuthToken(plexUsername,plexPassword)
	}

	for plexSection in plexSectionsSplit:
		url = 'http://%s/library/sections/%s/refresh' % (plexIP, plexSection)
		try:
			r = requests.get(url,params=params,verify=False, timeout=10)
		except requests.Timeout or requests.ConnectionError or requests.HTTPError:
			if silentMode:
				print ('[WARNING] NOTIFYPLEX: Error Updating Section %s. Silent Failure Mode Activated' % plexSection)
				sys.exit(POSTPROCESS_SUCCESS)
			else:
				print ('[ERROR] NOTIFYPLEX: Error Opening URL. Check Network Connection and Plex Server IP, Port, and Section Numbers')
				sys.exit(POSTPROCESS_ERROR)
		print ('[INFO] NOTIFYPLEX: Targeted PLEX Update for Section %s Complete' % plexSection)

def showGUINotifcation(rawPHTIPs):

	dHeaders=os.environ['NZBPO_DHEADERS']=='yes'
	phtURL=rawPHTIPs.replace(' ','')
	phtURLSplit=phtURL.split(',')
	for phtURL in phtURLSplit:
		if  dHeaders:
			if properName != '' and properEP != '':
				guiText = properName + ' - ' + properEP
			elif properName != '' and properYear != '':
				guiText = properName + ' (' + properYear + ')'
			elif properName == '' and properEP == '':
				guiText = nzbName
			else:
				guiText = properName
		else:
			guiText=nzbName

		phtRpcURL = 'http://%s:3005/jsonrpc' % phtURL
		headers = {'content-type': 'application/json'}
		payLoad= {'id':1,'jsonrpc':'2.0','method':'GUI.ShowNotification','params':{'title':'Downloaded','message':guiText}}
		try:
			d = requests.post(phtRpcURL, data=json.dumps(payLoad), headers=headers, timeout=10)
			print ('[INFO] NOTIFYPLEX: GUI Notification to PHT Successful')
		except requests.exceptions.ConnectionError or requests.Timeout or requests.HTTPError:
			print ('[WARNING] NOTIFYPLEX: Plex GUI Notification Failed')


if ppStatus:

	if guiShow:
		phtURLs=os.environ['NZBPO_CLIENTSIP']
		showGUINotifcation(phtURLs)

	if refreshLibrary:
		plexIP=os.environ['NZBPO_PLEXIP']
		rawPlexSection=os.environ['NZBPO_CUSTOMPLEXSECTION']
		mCats = os.environ['NZBPO_MOVIESCAT']
		tCats = os.environ['NZBPO_TVCAT']

		if (refreshMode=='Custom'):
			refreshCustomSections(rawPlexSection,plexIP)
		elif (refreshMode=='Auto'):
			refreshAuto(mCats,tCats,plexIP)
		else:
			refreshCustomSections(rawPlexSection,plexIP)
			refreshAuto(mCats,tCats,plexIP)

	sys.exit(POSTPROCESS_SUCCESS)

else:
	print ('[ERROR] NOTIFYPLEX: Skipping Plex Update because download failed.')
	sys.exit(POSTPROCESS_NONE)


Revision 1: Formatting Changes

Revision 2: Added ability to refresh multiple Plex sections at once. Separate multiple sections with a comma (etc. plexSection=1,2)

Revision 3: Added GUI Notification for Plex Home Theater upon successful download. URL requests are now handled by "requests" library which is included in the zip.

Revision 4: Added Authentication with Plex.tv to allow for library refreshing. This was introduced with Plex Media Server version 0.9.11.4 which includes the Plex Home feature. Also added Silent Failure mode, in case you want NZBGet to report SUCCESS if contacting/authenticating with the Plex server fails. There will still be a warning message in the logs.

Revision 5: Added Auto Mode, which will automatically detect the NZBGet category and Plex sections. Added option to Disable Refresh (for users who only want GUI notification). Added ability to send GUI notifications to multiple clients. Changed plexSections to customPlexSections for Custom mode.

Revision 6: Fixed DNZB Header for Movie Year. GUI notification now displays year of movie, i.e. "The Guest (2014)"

Revision 7: Fixed XML Parsing for Plex Sections. Script now properly detects Movie and TV sections by "type" instead of "title"

Download Link: http://bit.ly/notifyplex
Last edited by mannibis on 02 Jun 2015, 23:46, edited 48 times in total.

hugbug
Developer & Admin
Posts: 7396
Joined: 09 Sep 2008, 11:58
Location: Germany

Re: [PP-Script] NotifyPlex

Post by hugbug » 19 Aug 2014, 13:54

I don't use Plex but since you've asked here is my feedback based purely on the script code and is not related to how well the script works :)
  • I would replace (1, 0) with (yes, no)

    Code: Select all

    # Auto Update Plex Library (yes, no).
    #
    # Activate if you want NotifyPlex to Automatically Update/Refresh your Plex Library
    #PlexUpdate=no
    Then where it is checked:

    Code: Select all

    	if plexUpdate=="yes":
  • Actually it looks like the script doesn't do anything if the option "PlexUpdate" is disabled. If that's true the option is superfluous because the user can just disable the script completely.
  • The description of the options must follow certain (not documented) format:

    Code: Select all

    # Plex Section you would like to Update (1 for Movies, 2 for TV, etc.)
    #plexSection=1
    • The first line of option description must end with dot. This is how NZBGet distinguish the short description from the rest. In this example there is no long description, so it's not a problem;
    • The text in braces in the first line is interpreted in a special way - it lists possible option values to choose from a combobox element. Since this is not what you wanted here, you should move that text to the long option description. The combobox wasn't shown here because you forget the dot at the end, one bug has compensated for another. :)
    • That's how it should be:

      Code: Select all

      # Plex Section you would like to Update.
      #
      #  Section numbers: 1 for Movies, 2 for TV, etc.
      #plexSection=1
  • You recommend to make a copy of the script if more than one section have to be updated. Instead you could allow for multiple sections be entered in the option plexSection (renamed to PlexSections):

    Code: Select all

    # Plex Sections you would like to Update.
    #  1 for Movies, 2 for TV, etc.
    # Multiple sections can be separated with commas.
    #PlexSections=1
    

    Code: Select all

    # This code is not tested:
    plex_sections=os.environ['NZBPO_PLEXSECTIONS'].split(',')
    for plexSection in plex_sections:
    	if plexUpdate=="1":
    		url = 'http://%s/library/sections/%s/refresh' % (plexIP, plexSection)
    
  • Small thing - there is a #-character at the line end in the description. The character is also visible in web-interface and needs to be deleted.

    Code: Select all

    # Post-Process to Update Plex Library Based on Section #
  • Also add missing trailing dots in the script description. The description (About NotifyPlex) will look better in web-interface (it detects paragraphs better).

    Code: Select all

    # Post-Process to Update Plex Library Based on Section.
    #
    # This script sends a Targeted Library Update URL to your Plex Media Server.
    #
    # NOTE: This script requires Python to be installed on your system.

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex

Post by mannibis » 19 Aug 2014, 14:02

Thanks for your feedback, will revise the script.

As for the copying of the script, this was to be able to set the PP-Script to certain categories. For someone with a Movies category, they would only want the Movies section to be updated, and the same for TV. This is the only way I can think of right now that would be able to do a refresh for different sections based on the category they are using the script with.

EDIT: Updated Attachment in main post to reflect formatting changes

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex

Post by mannibis » 22 Aug 2014, 00:40

Added ability to scan multiple Plex sections at once by separating section numbers with a comma.
Main post and script has been revised and updated.

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by mannibis » 07 Sep 2014, 04:33

Added GUI Notification for Plex Home Theater

Main Post is updated with new code and URL for download.
The script now uses the requests library.

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by mannibis » 22 Nov 2014, 23:00

The script has been updated to supported Plex Media Server 0.9.11.4, which at the time of writing this post is a Plex-Pass Only release. I noticed that the API call to refresh libraries wasn't working anymore and learned that you need to now authenticate with Plex.tv and get an authentication token before you can perform any API commands/methods. This should not affect users with older versions of Plex, as it only adds an authentication request, but note you will need to add your username and password to the NotifyPlex settings. You will also notice that NotifyPlex is now visible in the Devices section of Plex/Web ;)

I also added (at a user's request) Silent Failure mode, in case you want NZBGet to report SUCCESS if contacting/authenticating with the Plex server fails. There will still be a warning message in the logs. It is an option in the NotifyPlex settings called "silentFailure" and is off by default.

Main post is updated and the same link will bring you to the new updated version.

binreader
Posts: 20
Joined: 07 Oct 2014, 03:00

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by binreader » 23 Nov 2014, 02:55

thanks for the updates you workin hard!

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by mannibis » 29 Nov 2014, 23:15

Big changes in this Update...

Library Refresh Mode has now been implemented

Users no longer have to enter in section numbers or copy the script to refresh their TV shows and Movies separately. Library Refresh Mode is a new option that allows the user to choose how they want to script to refresh their library. 'Auto' mode will automatically refresh TV Shows and Movies sections. The script has been completely re-designed to auto-detect the NZBGet category and also auto-detect the Plex sections by polling the Plex Server's API to figure out what sections are for TV Shows and what sections are for Movies. The plexSections setting has been changed to customPlexSections, if the user would like to scan a section other than TV Shows or Movies. The Custom sections will only be scanned if the Library Refresh Mode is set to Custom or Both.

Added option to Disable Refresh (for users who only want GUI notifications).

Added ability to send GUI notifications to multiple clients.

rubylaser
Posts: 33
Joined: 06 Feb 2014, 14:47

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by rubylaser » 12 Dec 2014, 01:05

I can't get this to work. Attached is an image showing my settings. Plexmediaserver is running on the same machine as NZBGet. Everytime the postprocessing runs, I get an error of NotifyPlex: Failure. Any ideas to get this working? I'm running plexmediaserver 0.9.11.5 with Plex Home enabled.
Attachments
notify-plex-settings.png

mannibis
Posts: 57
Joined: 29 Jul 2014, 15:10

Re: [PP-Script] NotifyPlex - Library Update and GUI Notifica

Post by mannibis » 12 Dec 2014, 01:16

Are there any logs in the messages tab you can post? I need to see what type of error you are getting. Does it say that Plex.tv authentication is successful? Check the messages tab when you run it again (Actions -> Post Process Again) and paste the output if you can.

Also, double check the names of your movies category. Usually people have one category for movies in their NZBGet settings. Is "Movies > HD" the name of a category in Settings > Categories?

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests