Merge remote-tracking branch 'origin/master'

This commit is contained in:
Blacktwin 2018-03-23 10:51:01 -04:00
commit 78283403d5
50 changed files with 864 additions and 1273 deletions

View File

@ -3,10 +3,10 @@
[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4J6RPWZ9J9YML) [![PM](https://img.shields.io/badge/Reddit-Message-lightgrey.svg)](https://www.reddit.com/user/Blacktwin/) [![PM](https://img.shields.io/badge/Plex-Message-orange.svg)](https://forums.plex.tv/profile/discussions/Blacktwin) [![Issue](https://img.shields.io/badge/Submit-Issue-red.svg)](https://github.com/blacktwin/JBOPS/issues/new)
Most of these scripts utilize a combination of [PlexPy](https://github.com/JonnyWong16/plexpy), [python-plexapi](https://github.com/pkkid/python-plexapi), and [requests](http://docs.python-requests.org/en/master/user/install/#install).
Most of these scripts utilize a combination of [Tautulli](https://github.com/Tautulli/Tautulli), [python-plexapi](https://github.com/pkkid/python-plexapi), and [requests](http://docs.python-requests.org/en/master/user/install/#install).
## Notice:
These scripts have not been tested using Tautulli. The improvements in Tautulli may cause errors with scripts that pull data from Tautulli, especailly metadata. If you come into a problem please create an issue and reference the script that errors out with Tautulli. Once Tautulli is out of Beta I'll look into which scripts need updated and which can be removed.
Updated for Tautulli. Use plexpy-branch if you are still using PlexPy.
## Scripts List
[![Gist](https://img.shields.io/badge/gist-Blacktwin-green.svg)](https://gist.github.com/blacktwin)
@ -28,7 +28,7 @@ Scripts pulled from my gist profile.
<a href="https://github.com/blacktwin/JBOPS/raw/master/maps/World_map_example.PNG"><img src="https://img.shields.io/badge/Image-World_map-blue.svg" alt=""</a>
<a href="https://github.com/blacktwin/JBOPS/blob/master/maps/geojson_example.geojson"><img src="https://img.shields.io/badge/Image-geojson-blue.svg" alt=""</a></td>
<td><a href="../master/maps/ips_to_maps.py"ips_to_maps>Maps</a></td>
<td>Using PlexPy data, draw a map connecting Server to Clients based on IP addresses.</td>
<td>Using Tautulli data, draw a map connecting Server to Clients based on IP addresses.</td>
</tr>
</table>
</details>
@ -69,8 +69,8 @@ Scripts pulled from my gist profile.
<td></td>
<td><a href="../master/killstream/wait_kill_pause_notify_main.py">wait_kill_pause_notify_main</a></td>
<td>
Receive session_key from PlexPy when paused. Use sub-script <a href="../master/killstream/wait_kill_pause_notify_sub.py">wait_kill_pause_notify_sub</a>
to wait for X time then check if still paused. If so, kill. Toggle whether you'd like to be notified through a PlexPy notification agent.
Receive session_key from Tautulli when paused. Use sub-script <a href="../master/killstream/wait_kill_pause_notify_sub.py">wait_kill_pause_notify_sub</a>
to wait for X time then check if still paused. If so, kill. Toggle whether you'd like to be notified through a Tautulli notification agent.
</td>
</tr>
<tr>
@ -97,7 +97,7 @@ Scripts pulled from my gist profile.
<tr>
<td></td>
<td><a href="../master/killstream/ip_whitelist.py">ip_whitelist</a></td>
<td>Receive session_key and IP from PlexPy when playback starts. Use IP to check against whitelist. If not in whitelist use session_key to determine stream and kill.</td>
<td>Receive session_key and IP from Tautulli when playback starts. Use IP to check against whitelist. If not in whitelist use session_key to determine stream and kill.</td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/88fce565c8ecf56839641f22f4c5c422"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -107,7 +107,7 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/d47d3ada86d02a494f9dc33e50dd15b5"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/killstream/kill_else_if_buffering.py">kill_else_if_buffering</a></td>
<td>Kill concurrent transcode streams of other users if Admin user is experiencing buffering warnings from PlexPy.</td>
<td>Kill concurrent transcode streams of other users if Admin user is experiencing buffering warnings from Tautulli.</td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/6d08b94ca3e80d3ed0bb3c7172fae21d"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -137,7 +137,7 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/14d400a0f442da465389164fa046647a"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/killstream/kill_trans_pause.py">kill_trans_pause</a></td>
<td>Kill Plex paused video transcoding streams using PlexPy.</td>
<td>Kill Plex paused video transcoding streams using Tautulli.</td>
</tr>
</table>
</details>
@ -160,12 +160,12 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/e6d589a9af9bdf168717951083861e93"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/notify/find_unwatched_notify.py">find_unwatched_notify</a></td>
<td>Find what was added TFRAME ago and not watched and notify admin using PlexPy.</td>
<td>Find what was added TFRAME ago and not watched and notify admin using Tautulli.</td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/1094dcf38249f36c8d374e0cba7a86cd"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/notify/notify_added_custom.py">notify_added_custom</a></td>
<td>Send an email with what was added to Plex in the past week using PlexPy. Email includes title (TV: Show Name: Episode Name; Movie: Movie Title), time added, image, and summary.</td>
<td>Send an email with what was added to Plex in the past week using Tautulli. Email includes title (TV: Show Name: Episode Name; Movie: Movie Title), time added, image, and summary.</td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/099c07d8099c18a378bba6415d9253ba"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -223,7 +223,7 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/f4149c296f2d1ffd1cbd863c37bb3a3c"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/utility/bypass_auth_name.py">bypass_auth_name</a></td>
<td>Use PlexPy to pull last IP address from user and add to List of IP addresses and networks that are allowed without auth in Plex. </td>
<td>Use Tautulli to pull last IP address from user and add to List of IP addresses and networks that are allowed without auth in Plex. </td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/0332f2dc9534bdf412ff3f664e9513c0"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -238,7 +238,7 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/603d5da5b70b366e98d0d82d1aa1a470"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/utility/find_unwatched.py">find_unwatched</a></td>
<td>Find what was added TFRAME ago and not watched using PlexPy. </td>
<td>Find what was added TFRAME ago and not watched using Tautulli. </td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/f435aa0ccd498b0840d2407d599bf31d"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -305,7 +305,7 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/21823b3394f5b077d42495b21570b593"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/reporting/added_to_plex.py">added_to_plex</a></td>
<td>Find when media was added between STARTFRAME and ENDFRAME to Plex through PlexPy.</td>
<td>Find when media was added between STARTFRAME and ENDFRAME to Plex through Tautulli.</td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/f070dff29ddbeb87973be9c0a94a1df7"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
@ -320,12 +320,12 @@ Scripts pulled from my gist profile.
<tr>
<td><a href="https://gist.github.com/blacktwin/561c3a404754eb7b9e543867619d3251"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/reporting/drive_check.py">drive_check</a></td>
<td>Check if drive exists. If not then notify via PlexPy notifier agent. </td>
<td>Check if drive exists. If not then notify via Tautulli notifier agent. </td>
</tr>
<tr>
<td><a href="https://gist.github.com/blacktwin/bd905d39ab71c5d7c628e27fddd1086e"><img src="https://img.shields.io/badge/gist-original-green.svg"></a></td>
<td><a href="../master/reporting/userplays_weekly_reporting.py">userplays_weekly_reporting</a></td>
<td>Use PlexPy to count how many plays per user occurred this week and send email via PlexPy.</td>
<td>Use Tautulli to count how many plays per user occurred this week and send email via Tautulli.</td>
</tr>
</table>
@ -334,26 +334,43 @@ Scripts pulled from my gist profile.
----
<details>
<summary>Setting Up PlexPy for Custom Scripts</summary>
<summary>Setting Up Tautulli for Custom Scripts</summary>
#### Enabling Scripts in PlexPy:
#### Enabling Scripts in Tautulli:
Settings > Notification Agents > Click the Scripts gear
Taultulli > Settings > Notification Agents > Add a Notification Agent > Script
- [ ] Set scripts location to location of your scripts
#### Configuration
Taultulli > Settings > Notification Agents > New Script > Configuration:
- [ ] Set scripts location to location of your script
- [ ] Scroll down to option you want to use and select the script from the drop down menu
- [ ] Set desired Script Timeout value
- [ ] Optional - Add a description of the script for easy reference
- [ ] Save
Settings > Notification Agents > Click the Bell next to Scripts
#### Triggers
Taultulli > Settings > Notification Agents > New Script > Triggers:
- [ ] Check desired trigger
- [ ] Close
Settings > Notifications > Click Script
- [ ] Enter in the Script Arguments
- [ ] Save
#### Conditions
Taultulli > Settings > Notification Agents > New Script > Conditions:
- [ ] Set desired conditions
- [ ] Save
For more information on Tautulli conditions see [here](https://github.com/Tautulli/Tautulli-Wiki/wiki/Custom-Notification-Conditions)
#### Script Arguments
Taultulli > Settings > Notification Agents > New Script > Script Arguments:
- [ ] Select desired trigger
- [ ] Input desired notification parameters (List of parameters will likely be found inside script)
- [ ] Save
- [ ] Close
</details>
@ -364,21 +381,15 @@ Settings > Notifications > Click Script
<details>
<summary>Plex</summary>
- [ ] PLEX_HOST - Local IP to connect to Plex ('localhost', '192.168.0.x', '127.0.0.1', etc.)
- [ ] PLEX_PORT - Port number used by Plex (default: 32400)
- [ ] PLEX_SSL - http:// or https://? '' if http and 's' if https
- [ ] PLEX_TOKEN - [Plex](https://support.plex.tv/hc/en-us/articles/204059436-Finding-an-authentication-token-X-Plex-Token) or PlexPy Settings > Plex.tv Account > PMS Token
- [ ] PLEX_URL - Local/Remote IP to connect to Plex ('http://localhost:32400', 'https://x.x.x.x:32412', etc.)
- [ ] PLEX_TOKEN - [Plex](https://support.plex.tv/hc/en-us/articles/204059436-Finding-an-authentication-token-X-Plex-Token) or Tautulli Settings > Plex.tv Account > PMS Token
</details>
<details>
<summary>PlexPy</summary>
<summary>Tautulli</summary>
- [ ] PLEXPY_URL - Local IP to connect to PlexPy ('localhost', '192.168.0.x', '127.0.0.1', etc.)
- [ ] PLEXPY_APIKEY - PlexPy Settings > Access Control > Enable API - API Key
- [ ] TAUTULLI_URL - Local/Remote IP to connect to Tautulli ('http://localhost:8181', 'https://x.x.x.x:8182', etc.)
- [ ] TAUTULLI_APIKEY - Tautulli Settings > Access Control > Enable API - API Key
</details>
</details>

View File

@ -1,187 +0,0 @@
'''
fetch function from https://gist.github.com/Hellowlol/ee47b6534410b1880e19
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on pause
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Playback Pause: create_wait_kill_all.py
PlexPy > Settings > Notifications > Script > Script Arguments:
{session_key}
create_wait_kill_all.py creates a new file with the session_id (sub_script) as it's name.
PlexPy will timeout create_wait_kill_all.py after 30 seconds (default) but sub_script.py will continue.
sub_script will check if the stream's session_id is still pause or if playing as restarted.
If playback is restarted then sub_script will stop and delete itself.
If stream remains paused then it will be killed and sub_script will stop and delete itself.
Set TIMEOUT to max time before killing stream
Set INTERVAL to how often you want to check the stream status
'''
import os
import platform
import subprocess
import sys
from uuid import getnode
import unicodedata
import requests
## EDIT THESE SETTINGS ##
PLEX_HOST = ''
PLEX_PORT = 32400
PLEX_SSL = '' # s or ''
PLEX_TOKEN = ''
PLEXPY_APIKEY = 'xxxxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TIMEOUT = 120
INTERVAL = 20
REASON = 'Because....'
ignore_lst = ('test')
class Activity(object):
def __init__(self, data=None):
d = data or {}
self.video_decision = d['video_decision']
self.state = d['state']
self.session_key = d['session_key']
def get_get_activity():
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
'cmd': 'get_activity'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['sessions']
return [Activity(data=d) for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_activity' request failed: {0}.".format(e))
def fetch(path, t='GET'):
url = 'http{}://{}:{}/'.format(PLEX_SSL, PLEX_HOST, PLEX_PORT)
headers = {'X-Plex-Token': PLEX_TOKEN,
'Accept': 'application/json',
'X-Plex-Provides': 'controller',
'X-Plex-Platform': platform.uname()[0],
'X-Plex-Platform-Version': platform.uname()[2],
'X-Plex-Product': 'Plexpy script',
'X-Plex-Version': '0.9.5',
'X-Plex-Device': platform.platform(),
'X-Plex-Client-Identifier': str(hex(getnode()))
}
try:
if t == 'GET':
r = requests.get(url + path, headers=headers, verify=False)
elif t == 'POST':
r = requests.post(url + path, headers=headers, verify=False)
elif t == 'DELETE':
r = requests.delete(url + path, headers=headers, verify=False)
if r and len(r.content): # incase it dont return anything
return r.json()
else:
return r.content
except Exception as e:
print e
def kill_stream(sessionId, message, xtime, ntime, user, title, sessionKey):
headers = {'X-Plex-Token': PLEX_TOKEN}
params = {'sessionId': sessionId,
'reason': message}
activity = get_get_activity()
for a in activity:
if a.session_key == sessionKey:
if a.state == 'paused' and xtime == ntime:
sys.stdout.write("Killing {user}'s paused stream of {title}".format(user=user, title=title))
requests.get('http{}://{}:{}/status/sessions/terminate'.format(PLEX_SSL, PLEX_HOST, PLEX_PORT),
headers=headers, params=params)
return ntime
elif a.state in ('playing', 'buffering'):
sys.stdout.write("{user}'s stream of {title} is now {state}".format(user=user, title=title,
state=a.state))
return None
else:
return xtime
def find_sessionID(response):
sessions = []
for video in response['MediaContainer']['Video']:
if video['sessionKey'] == sys.argv[1]:
sess_id = video['Session']['id']
user = video['User']['title']
sess_key = video['sessionKey']
title = (video['grandparentTitle'] + ' - ' if video['type'] == 'episode' else '') + video['title']
title = unicodedata.normalize('NFKD', title).encode('ascii','ignore')
sessions.append((sess_id, user, title, sess_key))
else:
pass
for session in sessions:
if session[1] not in ignore_lst:
return session
else:
print("{}'s stream of {} is ignored.".format(session[1], session[2]))
return None
if __name__ == '__main__':
startupinfo = None
if os.name == 'nt':
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
response = fetch('status/sessions')
fileDir = fileDir = os.path.dirname(os.path.realpath(__file__))
try:
if find_sessionID(response):
stream_info = find_sessionID(response)
file_name = "{}.py".format(stream_info[0])
full_path = os.path.join(fileDir, file_name)
file = 'from time import sleep\n' \
'import sys, os\n' \
'from {script} import kill_stream \n' \
'message = "{REASON}"\n' \
'sessionID = os.path.basename(sys.argv[0])[:-3]\n' \
'x = 0\n' \
'n = {ntime}\n' \
'try:\n' \
' while x < n and x is not None:\n' \
' sleep({xtime})\n' \
' x += kill_stream(sessionID, message, {xtime}, n, "{user}", "{title}", "{sess_key}")\n' \
' kill_stream(sessionID, message, {ntime}, n, "{user}", "{title}", "{sess_key}")\n' \
' os.remove(sys.argv[0])\n' \
'except TypeError as e:\n' \
' os.remove(sys.argv[0])'.format(script=os.path.basename(__file__)[:-3],
ntime=TIMEOUT, xtime=INTERVAL, REASON=REASON,
user=stream_info[1], title=stream_info[2], sess_key=stream_info[3])
with open(full_path, "w+") as output:
output.write(file)
subprocess.Popen([sys.executable, full_path], startupinfo=startupinfo)
exit(0)
except TypeError as e:
print(e)
pass

View File

@ -1,172 +0,0 @@
'''
fetch function from https://gist.github.com/Hellowlol/ee47b6534410b1880e19
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on pause
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Playback Pause: create_wait_kill_trans.py
PlexPy > Settings > Notifications > Script > Script Arguments:
{session_key}
create_wait_kill_trans.py creates a new file with the session_id (sub_script) as it's name.
PlexPy will timeout create_wait_kill_trans.py after 30 seconds (default) but sub_script.py will continue.
sub_script will check if the transcoding and stream's session_id is still pause or if playing as restarted.
If playback is restarted then sub_script will stop and delete itself.
If stream remains paused then it will be killed and sub_script will stop and delete itself.
Set TIMEOUT to max time before killing stream
Set INTERVAL to how often you want to check the stream status
'''
import os
import platform
import subprocess
import sys
from uuid import getnode
import unicodedata
import requests
## EDIT THESE SETTINGS ##
PLEX_HOST = ''
PLEX_PORT = 32400
PLEX_SSL = '' # s or ''
PLEX_TOKEN = 'xxxxx'
TIMEOUT = 30
INTERVAL = 10
REASON = 'Because....'
ignore_lst = ('test')
def fetch(path, t='GET'):
url = 'http{}://{}:{}/'.format(PLEX_SSL, PLEX_HOST, PLEX_PORT)
headers = {'X-Plex-Token': PLEX_TOKEN,
'Accept': 'application/json',
'X-Plex-Provides': 'controller',
'X-Plex-Platform': platform.uname()[0],
'X-Plex-Platform-Version': platform.uname()[2],
'X-Plex-Product': 'Plexpy script',
'X-Plex-Version': '0.9.5',
'X-Plex-Device': platform.platform(),
'X-Plex-Client-Identifier': str(hex(getnode()))
}
try:
if t == 'GET':
r = requests.get(url + path, headers=headers, verify=False)
elif t == 'POST':
r = requests.post(url + path, headers=headers, verify=False)
elif t == 'DELETE':
r = requests.delete(url + path, headers=headers, verify=False)
if r and len(r.content): # incase it dont return anything
return r.json()
else:
return r.content
except Exception as e:
print e
def kill_stream(sessionId, message, xtime, ntime, user, title, sessionKey):
headers = {'X-Plex-Token': PLEX_TOKEN}
params = {'sessionId': sessionId,
'reason': message}
response = fetch('status/sessions')
if response['MediaContainer']['Video']:
for video in response['MediaContainer']['Video']:
part = video['Media'][0]['Part'][0]
if video['sessionKey'] == sessionKey:
if xtime == ntime and video['Player']['state'] == 'paused' and part['decision'] == 'transcode':
sys.stdout.write("Killing {user}'s paused stream of {title}".format(user=user, title=title))
requests.get('http{}://{}:{}/status/sessions/terminate'.format(PLEX_SSL, PLEX_HOST, PLEX_PORT),
headers=headers, params=params)
return ntime
elif video['Player']['state'] in ('playing', 'buffering'):
sys.stdout.write("{user}'s stream of {title} is now {state}".
format(user=user, title=title, state=video['Player']['state']))
return None
else:
return xtime
else:
return None
def find_sessionID(response):
sessions = []
for video in response['MediaContainer']['Video']:
part = video['Media'][0]['Part'][0]
if video['sessionKey'] == sys.argv[1] and video['Player']['state'] == 'paused' \
and part['decision'] == 'transcode':
sess_id = video['Session']['id']
user = video['User']['title']
sess_key = video['sessionKey']
title = (video['grandparentTitle'] + ' - ' if video['type'] == 'episode' else '') + video['title']
title = unicodedata.normalize('NFKD', title).encode('ascii', 'ignore').translate(None,"'")
sessions.append((sess_id, user, title, sess_key))
else:
pass
print(sessions)
for session in sessions:
if session[1] not in ignore_lst:
return session
else:
print("{}'s stream of {} is ignored.".format(session[1], session[2]))
return None
if __name__ == '__main__':
startupinfo = None
if os.name == 'nt':
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
response = fetch('status/sessions')
fileDir = os.path.dirname(os.path.realpath(__file__))
try:
if find_sessionID(response):
stream_info = find_sessionID(response)
file_name = "{}.py".format(stream_info[0])
full_path = os.path.join(fileDir, file_name)
file = "from time import sleep\n" \
"import sys, os\n" \
"from {script} import kill_stream \n" \
"message = '{REASON}'\n" \
"sessionID = os.path.basename(sys.argv[0])[:-3]\n" \
"x = 0\n" \
"n = {ntime}\n" \
"try:\n" \
" while x < n and x is not None:\n" \
" sleep({xtime})\n" \
" x += kill_stream(sessionID, message, {xtime}, n, '{user}', '{title}', '{sess_key}')\n" \
" kill_stream(sessionID, message, {ntime}, n, '{user}', '{title}', '{sess_key}')\n" \
" os.remove(sys.argv[0])\n" \
"except TypeError as e:\n" \
" os.remove(sys.argv[0])".format(script=os.path.basename(__file__)[:-3],
ntime=TIMEOUT, xtime=INTERVAL, REASON=REASON,
user=stream_info[1], title=stream_info[2],
sess_key=stream_info[3])
with open(full_path, "w+") as output:
output.write(file)
subprocess.Popen([sys.executable, full_path], startupinfo=startupinfo)
exit(0)
except TypeError as e:
print(e)
pass

View File

@ -1,198 +0,0 @@
# 1. Install the requests module for python.
# pip install requests
# 2. Add script arguments in PlexPy. The following script arguments are available by default. More can be added below.
# -ip {ip_address} -us {user} -med {media_type} -tt {title} -pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
import argparse
import requests
import sys
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
AGENT_ID = 10 # The notification agent ID for PlexPy
# 10 Email
# 15 Scripts
# 17 Browser
# Replace LAN IP addresses that start with the LAN_SUBNET with a WAN IP address
# to retrieve geolocation data. Leave REPLACEMENT_WAN_IP blank for no replacement.
LAN_SUBNET = ('192.168')
REPLACEMENT_WAN_IP = ''
# The notification subject and body
# - Use "{p.argument}" for script arguments
# - Use "{g.value}" for geolocation data
# - Use "{u.value}" for user data
SUBJECT_TEXT = "PlexPy Notification"
BODY_TEXT = """\
<html>
<head></head>
<body>
<p>Hi!<br>
<br><a href="mailto:{u.email}"><img src="{u.user_thumb}" alt="Poster unavailable" height="50" width="50"></a> {p.user} has watched {p.media_type}:{p.title}<br>
<br>On {p.platform}[{p.player}] in <a href="http://maps.google.com/?q={g.latitude},{g.longitude}">{g.city}, {g.country}</a>.<br>
<br>At {p.timestamp} on {p.datestamp}.<br>
<br>IP address: {p.ip_address}<br>
<br>User email is: {u.email}<br>
<br>TEst area Data:{uip.data} <br>
</p>
</body>
</html>
"""
## CODE BELOW ##
##Geo Space##
class GeoData(object):
def __init__(self, data=None):
data = data or {}
self.continent = data.get('continent', 'N/A')
self.country = data.get('country', 'N/A')
self.region = data.get('region', 'N/A')
self.city = data.get('city', 'N/A')
self.postal_code = data.get('postal_code', 'N/A')
self.timezone = data.get('timezone', 'N/A')
self.latitude = data.get('latitude', 'N/A')
self.longitude = data.get('longitude', 'N/A')
self.accuracy = data.get('accuracy', 'N/A')
##USER Space##
class UserEmail(object):
def __init__(self, data=None):
data = data or {}
self.email = data.get('email', 'N/A')
self.user_id = data.get('user_id', 'N/A')
self.user_thumb = data.get('user_thumb', 'N/A')
##API Space##
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
'cmd': 'get_geoip_lookup',
'ip_address': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
data = response['response']['data']
if data.get('error'):
raise Exception(data['error'])
else:
sys.stdout.write("Successfully retrieved geolocation data.")
return GeoData(data=data)
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_geoip_lookup' request failed: {0}.".format(e))
return GeoData()
def get_user_email(user_id=''):
# Get the user email from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
'cmd': 'get_user',
'user_id': user_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
data = response['response']['data']
if data.get('error'):
raise Exception(data['error'])
else:
sys.stdout.write("Successfully retrieved user email data.")
return UserEmail(data=data)
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
return UserEmail()
def send_notification(arguments=None, geodata=None, useremail=None, user_address=None):
# Format notification text
try:
subject = SUBJECT_TEXT.format(p=arguments, g=geodata, u=useremail)
body = BODY_TEXT.format(p=arguments, g=geodata, u=useremail)
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
return None
if __name__ == '__main__':
# Parse arguments from PlexPy
parser = argparse.ArgumentParser()
parser.add_argument('-ip', '--ip_address', action='store', default='',
help='The IP address of the stream')
parser.add_argument('-us', '--user', action='store', default='',
help='Username of the person watching the stream')
parser.add_argument('-uid', '--user_id', action='store', default='',
help='User_ID of the person watching the stream')
parser.add_argument('-med', '--media_type', action='store', default='',
help='The media type of the stream')
parser.add_argument('-tt', '--title', action='store', default='',
help='The title of the media')
parser.add_argument('-pf', '--platform', action='store', default='',
help='The platform of the stream')
parser.add_argument('-pl', '--player', action='store', default='',
help='The player of the stream')
parser.add_argument('-da', '--datestamp', action='store', default='',
help='The date of the stream')
parser.add_argument('-ti', '--timestamp', action='store', default='',
help='The time of the stream')
parser.add_argument('-sn', '--show_name', action='store', default='',
help='The name of the TV show')
parser.add_argument('-ena', '--episode_name', action='store', default='',
help='The name of the episode')
parser.add_argument('-ssn', '--season_num', action='store', default='',
help='The season number of the TV show')
parser.add_argument('-enu', '--episode_num', action='store', default='',
help='The episode number of the TV show')
parser.add_argument('-srv', '--plex_server', action='store', default='',
help='The name of the Plex server')
parser.add_argument('-pos', '--poster', action='store', default='',
help='The poster url')
parser.add_argument('-sum', '--summary', action='store', default='',
help='The summary of the TV show')
parser.add_argument('-lbn', '--library_name', action='store', default='',
help='The name of the TV show')
p = parser.parse_args()
# Check to make sure there is an IP address before proceeding
if p.ip_address:
if p.ip_address.startswith(LAN_SUBNET) and REPLACEMENT_WAN_IP:
ip_address = REPLACEMENT_WAN_IP
else:
ip_address = p.ip_address
g = get_geoip_info(ip_address=ip_address)
u = get_user_email(user_id=p.user_id)
send_notification(arguments=p, geodata=g, useremail=u)
else:
sys.stdout.write("No IP address passed from PlexPy.")

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
'''
Receive session_key and IP from PlexPy when playback starts.
Receive session_key and IP from Tautulli when playback starts.
Use IP to check against whitelist.
If not in whitelist use session_key to determine stream and kill.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: ip_whitelist.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
{session_key} {ip_address}
'''
@ -24,17 +24,17 @@ from plexapi.server import PlexServer
PLEX_TOKEN = 'xxxxxx'
PLEX_URL = 'http://localhost:32400'
PLEXPY_APIKEY = 'xxxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
IP_WHITELIST = ['10.10.0.12'] # List IP addresses.
IGNORE_LST = ('') # List usernames that should be ignored.
REASON = 'IP Address: {} was not found in whitelist.'
AGENT_ID = 14 # Notification agent ID for PlexPy
NOTIFIER_ID = 14 # Notification agent ID for Tautulli
# Find Notification agent ID here:
# https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
# Tautulli Settings -> NOTIFICATION AGENTS -> :bell: Agent (NotifierID - {Description)
SUBJECT_TEXT = "IP Whitelist Violation"
BODY_TEXT = "Killed {user}'s stream of {title}. IP: {ip} not in whitelist"
@ -56,23 +56,23 @@ def send_notification(subject_text, body_text):
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None

View File

@ -2,16 +2,16 @@
If user has 2* or more concurrent streams kill all user's streams
*PlexPy > Settings > Notification> User Concurrent Stream Threshold
The number of concurrent streams by a single user for PlexPy to trigger a notification. Minimum 2.
*Tautulli > Settings > Notification> User Concurrent Stream Threshold
The number of concurrent streams by a single user for Tautulli to trigger a notification. Minimum 2.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on user concurrent streams
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback User Concurrent Streams: kill_more_than.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{user}
"""

View File

@ -1,10 +1,10 @@
"""
Kill Plex streams based on device.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_device.py
"""
@ -18,7 +18,7 @@ PLEX_URL = 'http://localhost:32400'
DEFAULT_REASON = 'This stream has ended due to your device type.'
# Find platforms that have history in PlexPy in Play count by platform and stream type Graph
# Find platforms that have history in Tautulli in Play count by platform and stream type Graph
DEVICES = {'Android': 'Andriod message',
'Chrome': 'Chrome message',
'Plex Media Player': 'PMP message',

View File

@ -5,10 +5,10 @@ kill stream will list why it was killed ('Server Admin's stream take priority an
concurrent streams'). Message will also include an approximation of when the other concurrent stream
will finish, stream that is closest to finish will be used.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on buffer warning
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Buffer Warnings: kill_else_if_buffering.py
'''

View File

@ -1,15 +1,15 @@
"""
If user has 2* or more concurrent streams and the IP of the 2nd stream differs from 1st kill 2nd.
If 2nd stream IP is the same as 1st stream don't kill.
*PlexPy > Settings > Notification> User Concurrent Stream Threshold
The number of concurrent streams by a single user for PlexPy to trigger a notification. Minimum 2.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
*Tautulli > Settings > Notification> User Concurrent Stream Threshold
The number of concurrent streams by a single user for Tautulli to trigger a notification. Minimum 2.
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on user concurrent streams
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback User Concurrent Streams: kill_more_than.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username} {ip_address} {session_key}
"""

View File

@ -1,13 +1,13 @@
"""
Kill stream of user if they are accessing Plex from outside network
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_outsider_stream.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username}
"""

View File

@ -1,10 +1,10 @@
"""
Kill stream if bitrate is > BITRATE_LIMIT
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_session_bitrate.py
"""

View File

@ -2,13 +2,13 @@
Limit number of plays of TV Show episodes during time of day.
Idea is to reduce continuous plays while sleeping.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_time.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username} {media_type} {grandparent_rating_key}
"""
@ -20,8 +20,8 @@ from time import time as ttime
from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
@ -51,16 +51,16 @@ sess.verify = False
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
def get_get_history(username):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(username):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': username,
'start_date': TODAY,
'order_column': 'date'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
@ -70,7 +70,7 @@ def get_get_history(username):
return [ep_watched, stopped_time[0]]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def kill_session(user):
@ -85,7 +85,7 @@ def kill_session(user):
if media_type is not 'episode':
exit()
watched_count, last_stop = get_get_history(username)
watched_count, last_stop = get_history(username)
if abs(last_stop - unix_time) > 20:
exit()

View File

@ -1,10 +1,10 @@
"""
Kill Plex video transcoding streams only. All audio streams are left alone.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_trans_exp_audio.py
"""
@ -19,7 +19,7 @@ PLEX_URL = 'http://localhost:32400'
DEFAULT_REASON = 'This stream has ended due to requiring video transcoding. ' \
'Please raise your Remote Quality to Original to play this content.'
# Find platforms that have history in PlexPy in Play count by platform and stream type Graph
# Find platforms that have history in Tautulli in Play count by platform and stream type Graph
DEVICES = {'Android': 'Andriod message',
'Chrome': 'Chrome message',
'Plex Media Player': 'PMP message',

View File

@ -1,13 +1,13 @@
"""
Kill Plex transcoding streams from specific libraries
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_trans_library.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
{section_id} {session_key}
"""
@ -24,7 +24,7 @@ TARGET_LIBRARIES = ['1', '2'] # Library IDs
DEFAULT_REASON = 'Stream terminated due to video transcoding of {} content. ' \
'Please set your device to use "Original" quality.'.format(', '.join(TARGET_LIBRARIES))
# Find platforms that have history in PlexPy in Play count by platform and stream type Graph
# Find platforms that have history in Tautulli in Play count by platform and stream type Graph
DEVICES = {'Android': 'Andriod message',
'Chrome': 'Chrome message',
'Plex Media Player': 'PMP message',
@ -32,7 +32,7 @@ DEVICES = {'Android': 'Andriod message',
USER_IGNORE = ('') # ('Username','User2')
PLEXPY_LOG = 'Killing {user}\'s stream of {title} due to video transcoding content from section {section}.'
TAUTULLI_LOG = 'Killing {user}\'s stream of {title} due to video transcoding content from section {section}.'
##
sess = requests.Session()
@ -57,5 +57,5 @@ if __name__ == '__main__':
trans_dec = session.transcodeSessions[0].videoDecision
if trans_dec == 'transcode':
reason = DEVICES.get(session.players[0].platform, DEFAULT_REASON)
print(PLEXPY_LOG.format(user=username, title=title, section=section_id))
print(TAUTULLI_LOG.format(user=username, title=title, section=section_id))
session.stop(reason=reason)

View File

@ -1,13 +1,13 @@
"""
Kill Plex paused video transcoding streams.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback pause
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Pause: kill_trans_pause.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
{session_key}
"""

View File

@ -2,10 +2,10 @@
Kill Plex paused video transcoding streams and receive notification.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback pause
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Pause: kill_trans_pause.py
"""
@ -18,8 +18,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEX_URL = 'http://localhost:32400'
PLEX_TOKEN = 'xxxxx'
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
KILL_MESSAGE = 'This stream has ended due to being paused and transcoding.'
@ -28,9 +28,9 @@ USER_IGNORE = ('') # ('Username','User2')
SUBJECT_TEXT = "Killed Paused Transcoded Stream."
BODY_TEXT = "Killed {user}'s paused transcoded stream of {title}."
AGENT_ID = 14 # Notification agent ID for PlexPy
NOTIFIER_ID = 14 # Notification agent ID for Tautulli
# Find Notification agent ID here:
# https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
# Tautulli Settings -> NOTIFICATION AGENTS -> :bell: Agent (NotifierID - {Description)
##/EDIT THESE SETTINGS ##
@ -39,23 +39,23 @@ sess.verify = False
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
def send_notification(subject_text, body_text):
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject_text,
'body': body_text}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None

View File

@ -1,13 +1,13 @@
"""
Kill Plex transcoding streams only. Checks original quality.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: kill_trans_quality.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
{rating_key}
"""
@ -31,7 +31,7 @@ DEVICES = {'Android': 'Andriod message',
USER_IGNORE = ('') # ('Username','User2')
PLEXPY_LOG = 'Killing {user}\'s stream of {title} due to video transcoding of {original} content'
TAUTULLI_LOG = 'Killing {user}\'s stream of {title} due to video transcoding of {original} content'
##
sess = requests.Session()
@ -54,5 +54,5 @@ if __name__ == '__main__':
trans_dec = session.transcodeSessions[0].videoDecision
if sess_rating == str(rating_key) and orig_quality in TARGET_QUALITY and trans_dec == 'transcode':
reason = DEVICES.get(session.players[0].platform, DEFAULT_REASON)
print(PLEXPY_LOG.format(user=username, title=title,original=orig_quality))
print(TAUTULLI_LOG.format(user=username, title=title,original=orig_quality))
session.stop(reason=reason)

View File

@ -1,13 +1,13 @@
"""
Kill streams if user has played too much Plex Today.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: play_limit.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username} {section_id}
"""
@ -19,8 +19,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
PLEX_TOKEN = 'xxxxx'
PLEX_URL = 'http://localhost:32400'
@ -48,23 +48,23 @@ sess.verify = False
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
def get_get_history(username, section_id):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(username, section_id):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': username,
'section_id': section_id,
'start_date': TODAY}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['recordsFiltered']
return res_data
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def kill_session(user):
@ -82,6 +82,6 @@ for items in PLAY_LIMIT[username]:
section_id = items['section_id']
limit = items['limit']
if get_get_history(username, section_id) > limit:
if get_history(username, section_id) > limit:
print('User has reached play limit for today.')
kill_session(username)

View File

@ -1,13 +1,13 @@
"""
Kill streams if user has exceeded time limit on Plex server. Choose to unshare or remove user.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: time_limit.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username}
"""
@ -18,8 +18,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
@ -41,21 +41,21 @@ plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
sections_lst = [x.title for x in plex.library.sections()]
def get_get_history(username):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(username):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': username}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return sum([data['duration'] for data in res_data])
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def unshare(user, libraries):
@ -88,7 +88,7 @@ if TIME_LIMIT[username]['m']:
total_time += TIME_LIMIT[username]['m'] * 60
if get_get_history(username) > total_time:
if get_history(username) > total_time:
print('User has reached time limit.')
kill_session(username)
if TIME_LIMIT[username]['remove']:

View File

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
'''
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on pause
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Pause: wait_kill_pause_notify_main.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
{session_key}
wait_kill_pause_notify_main.py & wait_kill_pause_notify_sub.py should be in the same directory.
wait_kill_pause_notify_main.py executes sub_script wait_kill_pause_notify_sub.py.
PlexPy will timeout wait_kill_pause_notify_main.py after 30 seconds (default)
Tautulli will timeout wait_kill_pause_notify_main.py after 30 seconds (default)
but wait_kill_pause_notify_sub.py will continue.
wait_kill_pause_notify_sub will check if the stream's session_id is still paused or if playing as restarted.
@ -31,8 +31,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEX_TOKEN = ''
PLEX_URL = 'http://localhost:32400'
PLEXPY_APIKEY = '' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
TIMEOUT = '120'
INTERVAL = '20'
@ -44,10 +44,10 @@ USER_IGNORE = ('') # ('Username','User2')
SUBJECT_TEXT = "Killed Paused Transcoded Stream."
BODY_TEXT = "Killed {user}'s paused transcoded stream of {title}."
AGENT_ID = 10 # Notification agent ID for PlexPy
NOTIFIER_ID = 10 # Notification agent ID for Tautulli
# Find Notification agent ID here:
# https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
# AGENT = '' to disable notification
# Tautulli Settings -> NOTIFICATION AGENTS -> :bell: Agent (NotifierID - {Description)
# NOTIFIER_ID = '' to disable notification
sub_script = 'wait_kill_pause_notify_sub.py'
##/EDIT THESE SETTINGS ##
@ -60,23 +60,23 @@ sessionKey = sys.argv[1]
def send_notification(subject_text, body_text):
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject_text,
'body': body_text}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
@ -92,7 +92,7 @@ def kill_stream(session, xtime, ntime):
title = (session.grandparentTitle + ' - ' if session.type == 'episode' else '') + session.title
if state == 'paused' and xtime == ntime:
if AGENT_ID:
if NOTIFIER_ID:
send_notification(SUBJECT_TEXT, BODY_TEXT.format(user=username, title=title))
session.stop(reason=KILL_MESSAGE)
return ntime

View File

@ -4,7 +4,7 @@
wait_kill_pause_notify_main.py & wait_kill_pause_notify_sub.py should be in the same directory.
wait_kill_pause_notify_main.py executes sub_script wait_kill_pause_notify_sub.py.
PlexPy will timeout wait_kill_pause_notify_main.py after 30 seconds (default)
Tautulli will timeout wait_kill_pause_notify_main.py after 30 seconds (default)
but wait_kill_pause_notify_sub.py will continue.
wait_kill_pause_notify_sub will check if the stream's session_id is still paused or if playing as restarted.

View File

@ -0,0 +1,119 @@
"""
Description: Kill paused sessions if paused for X amount of time.
Author: samwiseg00
Requires: requests, plexapi
Enabling Scripts in Tautulli:
Taultulli > Settings > Notification Agents > Add a Notification Agent > Script
Configuration:
Taultulli > Settings > Notification Agents > New Script > Configuration:
Script Name: wait_kill_notify.py
Set Script Timeout: 0
Description: Killing long pauses
Save
Triggers:
Taultulli > Settings > Notification Agents > New Script > Triggers:
Check: Playback Pause
Save
Conditions:
Taultulli > Settings > Notification Agents > New Script > Conditions:
Set Conditions: Condition {1} | Username | is not | UsernameToExclude
Save
Script Arguments:
Taultulli > Settings > Notification Agents > New Script > Script Arguments:
Select: Playback Pause
Arguments: {session_key} {user} {title} TIMEOUT INTERVAL
Save
Close
Example:
{session_key} {user} {title} 1200 20
This will tell the script to kill the stream after 20 minutes and check every 20 seconds
"""
import os
import sys
from time import sleep
from datetime import datetime
from plexapi.server import PlexServer
import requests
PLEX_FALLBACK_URL = 'http://127.0.0.1:32400'
PLEX_FALLBACK_TOKEN = ''
PLEX_URL = os.getenv('PLEX_URL', PLEX_FALLBACK_URL)
PLEX_TOKEN = os.getenv('PLEX_TOKEN', PLEX_FALLBACK_TOKEN)
PLEX_OVERRIDE_URL = ''
PLEX_OVERRIDE_TOKEN = ''
if PLEX_OVERRIDE_URL:
PLEX_URL = PLEX_OVERRIDE_URL
if PLEX_OVERRIDE_TOKEN:
PLEX_TOKEN = PLEX_OVERRIDE_TOKEN
sess = requests.Session()
sess.verify = False
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
sessionKey = sys.argv[1]
username = sys.argv[2]
streamTitle = sys.argv[3]
timeout = int(sys.argv[4])
interval = int(sys.argv[5])
seconds = int(timeout)
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
periods = [('hours', hours), ('minutes', minutes), ('seconds', seconds)]
time_string = ', '.join('{} {}'.format(value, name)
for name, value in periods
if value)
start = datetime.now()
countdown = 0
counter = timeout + interval + 100
while countdown < counter and countdown is not None:
foundSession = False
for session in plex.sessions():
if session.sessionKey == int(sessionKey):
foundSession = True
state = session.players[0].state
if state == 'paused':
now = datetime.now()
diff = now - start
if diff.total_seconds() >= timeout:
session.stop(reason="This stream has ended due to being paused for over {}.".format(time_string))
print ("Killed {}'s {} paused stream of {}.".format(username, time_string, streamTitle))
sys.exit(0)
else:
sleep(interval)
counter = counter - interval
elif state == 'playing' or state == 'buffering':
print ("{} resumed the stream of {} so we killed the script.".format(username, streamTitle))
sys.exit(0)
if not foundSession:
print ("Session key ({}) for user {} not found while playing {}. "
"The player may have gone to a paused then stopped state.".format(sessionKey, username, streamTitle))
sys.exit(0)

View File

@ -1,13 +1,13 @@
"""
Kill streams if user has watched too much Plex Today.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: watch_limit.py
PlexPy > Settings > Notifications > Script > Script Arguments
Tautulli > Settings > Notifications > Script > Script Arguments
{username}
"""
@ -19,8 +19,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
PLEX_TOKEN = 'xxxxx'
PLEX_URL = 'http://localhost:32400'
@ -41,22 +41,22 @@ sess.verify = False
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
def get_get_history(username):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(username):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': username,
'start_date': TODAY}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return sum([data['watched_status'] for data in res_data])
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def kill_session(user):
@ -69,6 +69,6 @@ def kill_session(user):
session.stop(reason=MESSAGE)
if get_get_history(username) > WATCH_LIMIT[username]:
if get_history(username) > WATCH_LIMIT[username]:
print('User has reached watch limit for today.')
kill_session(username)

View File

@ -1,5 +1,5 @@
"""
Use PlexPy draw a map connecting Server to Clients based on IP addresses.
Use Tautulli draw a map connecting Server to Clients based on IP addresses.
optional arguments:
-h, --help show this help message and exit
@ -32,13 +32,11 @@ from collections import OrderedDict
import argparse
import numpy as np
import time
from collections import Counter
import webbrowser
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = '' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
# Replace LAN IP addresses that start with the LAN_SUBNET with a WAN IP address
# to retrieve geolocation data. Leave REPLACEMENT_WAN_IP blank for no replacement.
@ -56,16 +54,16 @@ SERVER_CITY = ''
SERVER_STATE = ''
SERVER_PLATFORM = 'Server'
DEFAULT_COLOR = '#A96A1C' # Plex Orange?
DEFAULT_COLOR = '#A96A1C' # Plex Orange?
PLATFORM_COLORS = {'Android': '#a4c639', # Green
'Roku':'#800080', # Purple
'Chromecast':'#ffff00', # Yellow
'Xbox One':'#ffffff', # White
'Chrome':'#ff0000', # Red
'Playstation 4':'#0000ff', # Blue
'iOS':'#8b4513', # Poop brown
'Samsung': '#0c4da2', # Blue
PLATFORM_COLORS = {'Android': '#a4c639', # Green
'Roku': '#800080', # Purple
'Chromecast': '#ffff00', # Yellow
'Xbox One': '#ffffff', # White
'Chrome': '#ff0000', # Red
'Playstation 4': '#0000ff', # Blue
'iOS': '#8b4513', # Poop brown
'Samsung': '#0c4da2', # Blue
'Windows': DEFAULT_COLOR,
'Xbox 360 App': DEFAULT_COLOR}
@ -95,19 +93,20 @@ class UserIPs(object):
self.play_count = d['play_count']
self.platform = d['platform']
def get_get_users_tables(users='', length=''):
# Get the users list from PlexPy
def get_users_tables(users='', length=''):
# Get the users list from Tautulli
if length:
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_users_table',
'length': length}
else:
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_users_table'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
if not length and not users:
@ -122,31 +121,32 @@ def get_get_users_tables(users='', length=''):
return [d['user_id'] for user in users for d in res_data if user == d['friendly_name']]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_users_tables' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_users_tables' request failed: {0}.".format(e))
def get_get_users_ips(user_id, length):
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_users_ips(user_id, length):
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user_ips',
'user_id': user_id,
'length': length}
'user_id': user_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserIPs(data=d) for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_users_ips' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_users_ips' request failed: {0}.".format(e))
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the geo IP lookup from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_geoip_lookup',
'ip_address': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
data = response['response']['data']
@ -158,21 +158,23 @@ def get_geoip_info(ip_address=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_geoip_lookup' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_geoip_lookup' request failed: {0}.".format(e))
pass
def get_stream_type_by_top_10_platforms():
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_stream_type_by_top_10_platforms'} # length is number of returns, default is 25
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['categories']
return res_data
except Exception as e:
sys.stderr.write("PlexPy API 'get_stream_type_by_top_10_platforms' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_stream_type_by_top_10_platforms' request failed: {0}.".format(e))
def add_to_dictlist(d, key, val):
if key not in d:
@ -183,13 +185,14 @@ def add_to_dictlist(d, key, val):
if (val['region'], val['city']) == (x['region'], x['city']):
x['location_count'] += 1
def get_geo_dict(length, users):
geo_dict = {SERVER_FRIENDLY: [{'lon': SERVER_LON, 'lat': SERVER_LAT, 'city': SERVER_CITY, 'region': SERVER_STATE,
'ip': REPLACEMENT_WAN_IP, 'play_count': 0, 'platform': SERVER_PLATFORM,
'location_count': 0}]}
for i in get_get_users_tables(users):
user_ip = get_get_users_ips(user_id=i, length=length)
for i in get_users_tables(users):
user_ip = get_users_ips(user_id=i, length=length)
city_cnt = 0
for a in user_ip:
try:
@ -201,8 +204,8 @@ def get_geo_dict(length, users):
add_to_dictlist(geo_dict, a.friendly_name, {'lon': str(g.longitude), 'lat': str(g.latitude),
'city': str(g.city), 'region': str(g.region),
'ip': ip, 'play_count': a.play_count,
'platform':a.platform, 'location_count': city_cnt})
'ip': ip, 'play_count': a.play_count,
'platform': a.platform, 'location_count': city_cnt})
except AttributeError:
print('User: {} IP: {} caused error in geo_dict.'.format(a.friendly_name, a.ip_address))
pass
@ -211,6 +214,7 @@ def get_geo_dict(length, users):
pass
return geo_dict
def get_geojson_dict(user_locations):
locs = []
for username, locations in user_locations.iteritems():
@ -255,13 +259,14 @@ def get_geojson_dict(user_locations):
"features": locs
}
def draw_map(map_type, geo_dict, filename, headless):
import matplotlib as mpl
if headless:
mpl.use("Agg")
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
## Map stuff ##
plt.figure(figsize=(16, 9), dpi=100, frameon=False, tight_layout=True)
lon_r = 0
@ -324,7 +329,7 @@ def draw_map(map_type, geo_dict, filename, headless):
# Keeping lines inside the Location. Plots outside Location will still be in legend
if float(data['lon']) != float(SERVER_LON) and float(data['lat']) != float(SERVER_LAT) and \
lon_l < float(data['lon']) < lon_r:
lon_l < float(data['lon']) < lon_r:
# Drawing lines from Server location to client location
if data['location_count'] > 1:
lines = m.plot(x, y, marker=marker, color=color, markersize=0,
@ -332,16 +337,14 @@ def draw_map(map_type, geo_dict, filename, headless):
# Adding dash sequence to 2nd, 3rd, etc lines from same city,state
for line in lines:
line.set_solid_capstyle('round')
dashes = [x * data['location_count'] for x in [5,8,5,8]]
dashes = [x * data['location_count'] for x in [5, 8, 5, 8]]
line.set_dashes(dashes)
else:
lines = m.plot(x, y, marker=marker, color=color, markersize=0, label=legend, alpha=.4, zorder=zord,
linewidth=2)
client_plot = m.plot(px, py, marker=marker, color=color, markersize=markersize,
label=legend, alpha=alph, zorder=zord)
m.plot(x, y, marker=marker, color=color, markersize=0, label=legend, alpha=.4, zorder=zord,
linewidth=2)
m.plot(px, py, marker=marker, color=color, markersize=markersize, label=legend, alpha=alph, zorder=zord)
handles, labels = plt.gca().get_legend_handles_labels()
idx = labels.index('Location: {}, {}, User: {}\nPlatform: {}, IP: {}, Play Count: {}'.
@ -376,16 +379,16 @@ def draw_map(map_type, geo_dict, filename, headless):
if __name__ == '__main__':
timestr = time.strftime("%Y%m%d-%H%M%S")
user_count = get_get_users_tables()
user_lst = sorted(get_get_users_tables('friendly_name', user_count))
user_count = get_users_tables()
user_lst = sorted(get_users_tables('friendly_name', user_count))
json_check = sorted([f for f in os.listdir('.') if os.path.isfile(f) and f.endswith(".json")], key=os.path.getmtime)
parser = argparse.ArgumentParser(description="Use PlexPy to draw map of user locations base on IP address.",
parser = argparse.ArgumentParser(description="Use Tautulli to draw map of user locations base on IP address.",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-l', '--location', default='NA', choices=['NA', 'EU','World', 'Geo'], metavar='',
parser.add_argument('-l', '--location', default='NA', choices=['NA', 'EU', 'World', 'Geo'], metavar='',
help='Map location. choices: (%(choices)s) \n(default: %(default)s)')
parser.add_argument('-c', '--count', nargs='?', type=int , default=2, metavar='',
parser.add_argument('-c', '--count', nargs='?', type=int, default=2, metavar='',
help='How many IPs to attempt to check. \n(default: %(default)s)')
parser.add_argument('-u', '--users', nargs='+', type=str ,default='all', choices=user_lst, metavar='',
parser.add_argument('-u', '--users', nargs='+', type=str, default='all', choices=user_lst, metavar='',
help='Space separated list of case sensitive names to process. Allowed names are: \n'
'%(choices)s \n(default: %(default)s)')
parser.add_argument('-i', '--ignore', nargs='+', type=str, default=None, choices=user_lst, metavar='',
@ -410,7 +413,7 @@ if __name__ == '__main__':
with open(''.join(opts.json)) as json_data:
geo_json = json.load(json_data)
else:
print(opts)
# print(opts)
if opts.ignore and opts.users == 'all':
users = [x for x in user_lst if x not in opts.ignore]
else:
@ -445,4 +448,5 @@ if __name__ == '__main__':
print(r.json()['html_url'])
webbrowser.open(r.json()['html_url'])
else:
print(geo_json)
draw_map(opts.location, geo_json, filename, opts.headless)

View File

@ -1,23 +1,23 @@
"""
Find what was added TFRAME ago and not watched and notify admin using PlexPy.
Find what was added TFRAME ago and not watched and notify admin using Tautulli.
TAUTULLI_URL + delete_media_info_cache?section_id={section_id}
"""
import requests
import sys
import time
TFRAME = 1.577e+7 # ~ 6 months in seconds
TFRAME = 1.577e+7 # ~ 6 months in seconds
TODAY = time.time()
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
LIBRARY_NAMES = ['My Movies', 'My TV Shows'] # Name of libraries you want to check.
SUBJECT_TEXT = "PlexPy Notification"
AGENT_ID = 10 # The email notification agent ID for PlexPy
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8183/' # Your Tautulli URL
LIBRARY_NAMES = ['Movies', 'TV Shows'] # Name of libraries you want to check.
SUBJECT_TEXT = "Tautulli Notification"
NOTIFIER_ID = 12 # The email notification agent ID for Tautulli
class LIBINFO(object):
@ -40,19 +40,21 @@ class METAINFO(object):
self.rating_key = d['rating_key']
self.media_type = d['media_type']
self.grandparent_title = d['grandparent_title']
self.file_size = d['file_size']
self.file = d['file']
media_info = d['media_info'][0]
parts = media_info['parts'][0]
self.file_size = parts['file_size']
self.file = parts['file']
def get_get_new_rating_keys(rating_key, media_type):
def get_new_rating_keys(rating_key, media_type):
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_new_rating_keys',
'rating_key': rating_key,
'media_type': media_type}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
@ -63,139 +65,141 @@ def get_get_new_rating_keys(rating_key, media_type):
return episode_lst
except Exception as e:
sys.stderr.write("PlexPy API 'get_new_rating_keys' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_new_rating_keys' request failed: {0}.".format(e))
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
'cmd': 'get_metadata'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['metadata']
res_data = response['response']['data']
return METAINFO(data=res_data)
except Exception as e:
# sys.stderr.write("PlexPy API 'get_get_metadata' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
pass
def get_get_library_media_info(section_id):
# Get the data on the PlexPy media info tables.
payload = {'apikey': PLEXPY_APIKEY,
def get_library_media_info(section_id):
# Get the data on the Tautulli media info tables.
payload = {'apikey': TAUTULLI_APIKEY,
'section_id': section_id,
'cmd': 'get_library_media_info',
'length': 10000}
'cmd': 'get_library_media_info'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [LIBINFO(data=d) for d in res_data if d['play_count'] is None and (TODAY - int(d['added_at'])) > TFRAME]
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def get_get_libraries_table():
# Get the data on the PlexPy libraries table.
payload = {'apikey': PLEXPY_APIKEY,
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries_table'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [d['section_id'] for d in res_data if d['section_name'] in LIBRARY_NAMES]
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries_table' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
def send_notification(BODY_TEXT):
def send_notification(body_text):
# Format notification text
try:
subject = SUBJECT_TEXT
body = BODY_TEXT
body = body_text
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
show_lst = []
notify_lst = []
glt = [lib for lib in get_get_libraries_table()]
libraries = [lib for lib in get_libraries_table()]
for i in glt:
for library in libraries:
try:
gglm = get_get_library_media_info(i)
for x in gglm:
library_media_info = get_library_media_info(library)
for lib in library_media_info:
try:
if x.media_type in ['show', 'episode']:
if lib.media_type in ['show', 'episode']:
# Need to find TV shows rating_key for episode.
show_lst += get_get_new_rating_keys(x.rating_key, x.media_type)
show_lst += get_new_rating_keys(lib.rating_key, lib.media_type)
else:
# Find movie rating_key.
show_lst += [int(x.rating_key)]
show_lst += [int(lib.rating_key)]
except Exception as e:
print("Rating_key failed: {e}").format(e=e)
print "Rating_key failed: {e}".format(e=e)
except Exception as e:
print("Library media info failed: {e}").format(e=e)
print "Library media info failed: {e}".format(e=e)
for i in show_lst:
for show in show_lst:
try:
x = get_get_metadata(str(i))
added = time.ctime(float(x.added_at))
if x.grandparent_title == '' or x.media_type == 'movie':
meta = get_metadata(str(show))
added = time.ctime(float(meta.added_at))
if meta.grandparent_title == '' or meta.media_type == 'movie':
# Movies
notify_lst += [u"<dt>{x.title} ({x.rating_key}) was added {when} and has not been"
u" watched.</dt> <dd>File location: {x.file}</dd> <br>".format(x=x, when=added)]
u" watched.</dt> <dd>File location: {x.file}</dd> <br>".format(x=meta, when=added)]
else:
# Shows
notify_lst += [u"<dt>{x.grandparent_title}: {x.title} ({x.rating_key}) was added {when} and has"
u" not been watched.<d/t> <dd>File location: {x.file}</dd> <br>".format(x=x, when=added)]
u" not been watched.<d/t> <dd>File location: {x.file}</dd> <br>".format(x=meta, when=added)]
except Exception as e:
print("Metadata failed. Likely end of range: {e}").format(e=e)
print "Metadata failed. Likely end of range: {e}".format(e=e)
if notify_lst:
BODY_TEXT = """\
<html>
<head></head>
<body>
<p>Hi!<br>
<br>Below is the list of {LIBRARY_NAMES} that have not been watched.<br>
<dl>
{notify_lst}
</dl>
</p>
</body>
</html>
""".format(notify_lst="\n".join(notify_lst).encode("utf-8"), LIBRARY_NAMES=" & ".join(LIBRARY_NAMES))
BODY_TEXT = """\
<html>
<head></head>
<body>
<p>Hi!<br>
<br>Below is the list of {LIBRARY_NAMES} that have not been watched.<br>
<dl>
{notify_lst}
</dl>
</p>
</body>
</html>
""".format(notify_lst="\n".join(notify_lst).encode("utf-8"),LIBRARY_NAMES=" & ".join(LIBRARY_NAMES))
send_notification(BODY_TEXT)
print(BODY_TEXT)
send_notification(BODY_TEXT)
else:
print('Nothing to report.')
exit()

View File

@ -1,5 +1,5 @@
"""
Send an email with what was added to Plex in the past week using PlexPy.
Send an email with what was added to Plex in the past week using Tautulli.
Email includes title (TV: Show Name: Episode Name; Movie: Movie Title), time added, image, and summary.
Uses:
@ -35,9 +35,10 @@ import uuid
import argparse
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['Movies', 'TV Shows'] # Name of libraries you want to check.
# Email settings
@ -49,7 +50,7 @@ email_server = 'smtp.gmail.com' # Email server (Gmail: smtp.gmail.com)
email_port = 587 # Email port (Gmail: 587)
email_username = '' # Your email username
email_password = '' # Your email password
email_subject = 'PlexPy Added Last {} day(s) Notification' #The email subject
email_subject = 'Tautulli Added Last {} day(s) Notification' #The email subject
# Default sizing for pictures
# Poster
@ -70,21 +71,20 @@ class METAINFO(object):
self.rating_key = d['rating_key']
self.media_type = d['media_type']
self.grandparent_title = d['grandparent_title']
self.file_size = d['file_size']
self.thumb = d['art']
self.summary = d['summary']
def get_get_recent(section_id, start, count):
def get_recent(section_id, start, count):
# Get the metadata for a media item. Count matters!
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'start': str(start),
'count': str(count),
'section_id': section_id,
'cmd': 'get_recently_added'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -93,86 +93,87 @@ def get_get_recent(section_id, start, count):
return res_data
except Exception as e:
sys.stderr.write("PlexPy API 'get_recently_added' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_recently_added' request failed: {0}.".format(e))
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
res_data = response['response']['data']['metadata']
res_data = response['response']['data']
return METAINFO(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_metadata' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
def get_get_libraries_table():
# Get the data on the PlexPy libraries table.
payload = {'apikey': PLEXPY_APIKEY,
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries_table'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [d['section_id'] for d in res_data if d['section_name'] in LIBRARY_NAMES]
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries_table' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
def update_library_media_info(section_id):
# Get the data on the PlexPy media info tables.
payload = {'apikey': PLEXPY_APIKEY,
# Get the data on the Tautulli media info tables.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_library_media_info',
'section_id': section_id,
'refresh': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.status_code
if response != 200:
print(r.content)
except Exception as e:
sys.stderr.write("PlexPy API 'update_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'update_library_media_info' request failed: {0}.".format(e))
def get_pms_image_proxy(thumb):
# Gets an image from the PMS and saves it to the image cache directory.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'pms_image_proxy',
'img': thumb}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload, stream=True)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload, stream=True)
return r.url
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_users_tables' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_users_tables' request failed: {0}.".format(e))
def get_get_users():
# Get the user list from PlexPy.
payload = {'apikey': PLEXPY_APIKEY,
def get_users():
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_users'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
return [d for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_rating_keys(TODAY, LASTDATE):
@ -185,7 +186,7 @@ def get_rating_keys(TODAY, LASTDATE):
while True:
# Assume all items will be returned in descending order of added_at
recent_items = get_get_recent(section_id, start, count)
recent_items = get_recent(section_id, start, count)
if all([recent_items]):
start += count
@ -205,7 +206,7 @@ def get_rating_keys(TODAY, LASTDATE):
def build_html(rating_key, height, width, pic_type):
meta = get_get_metadata(str(rating_key))
meta = get_metadata(str(rating_key))
added = time.ctime(float(meta.added_at))
# Pull image url
@ -286,12 +287,12 @@ def send_email(msg_text_lst, notify_lst, image_lst, to, days):
mailserver.login(email_username, email_password)
mailserver.sendmail(sender, to, message.as_string())
mailserver.quit()
print 'Email sent'
print('Email sent')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Send an email with what was added to Plex in the past week using PlexPy.")
parser = argparse.ArgumentParser(description="Send an email with what was added to Plex in the past week using Tautulli.")
parser.add_argument('-t', '--type', help='Metadata picture type from Plex.',
required= True, choices=['art', 'poster'])
parser.add_argument('-s', '--size', help='Metadata picture size from Plex {Height Width}.', nargs='*')
@ -320,17 +321,17 @@ if __name__ == '__main__':
width = art_w
# Find the libraries from LIBRARY_NAMES
glt = [lib for lib in get_get_libraries_table()]
glt = [lib for lib in get_libraries_table()]
# Update media info for libraries.
[update_library_media_info(i) for i in glt]
# Gather all users email addresses
if opts.users == ['all']:
[to.append(x['email']) for x in get_get_users() if x['email'] != '' and x['email'] not in to
[to.append(x['email']) for x in get_users() if x['email'] != '' and x['email'] not in to
and x['username'] not in opts.ignore]
elif opts.users != ['all'] and opts.users != 'self':
for get_users in get_get_users():
for get_users in get_users():
for arg_users in opts.users:
if arg_users in get_users['username']:
to = to + [str(get_users['email'])]

View File

@ -1,33 +1,32 @@
'''
"""
Delay Notification Agent message for concurrent streams
Arguments passed from PlexPy
Arguments passed from Tautulli
-u {user} -srv {server_name}
You can add more arguments if you want more details in the email body
Adding to PlexPy
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Adding to Tautulli
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on concurrent streams
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
User Concurrent Streams: notify_delay.py
PlexPy Settings > Notification Agents > Scripts (Gear) > Script Timeout: 0 to disable or set to > 180
'''
Tautulli Settings > Notification Agents > Scripts (Gear) > Script Timeout: 0 to disable or set to > 180
"""
import requests
import sys
import argparse
from time import sleep
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
CONCURRENT_TOTAL = 2
TIMEOUT = 180
INTERVAL = 20
AGENT_ID = 10 # Notification agent ID for PlexPy
NOTIFIER_ID = 10 # Notification notifier ID for Tautulli
# Find Notification agent ID here:
# https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
@ -44,49 +43,51 @@ BODY_TEXT = """\
"""
def get_get_activity():
def get_activity():
# Get the current activity on the PMS.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_activity'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['sessions']
return [d['user'] for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_activity' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_activity' request failed: {0}.".format(e))
pass
def send_notification(SUBJECT_TEXT, BODY_TEXT):
def send_notification(subject_text, body_text):
# Format notification text
try:
subject = SUBJECT_TEXT.format(p=p, total=cc_total)
body = BODY_TEXT.format(p=p, total=cc_total, time=TIMEOUT/60)
subject = subject_text.format(p=p, total=cc_total)
body = body_text.format(p=p, total=cc_total, time=TIMEOUT / 60)
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
if __name__ == '__main__':
parser = argparse.ArgumentParser()
@ -101,7 +102,7 @@ if __name__ == '__main__':
while x < TIMEOUT and x is not None:
# check if user still has concurrent streams
print('Checking concurrent stream count.')
cc_total = get_get_activity().count(p.user)
cc_total = get_activity().count(p.user)
if cc_total >= CONCURRENT_TOTAL:
print('{p.user} still has {total} concurrent streams.'.format(p=p, total=cc_total))
sleep(INTERVAL)

View File

@ -3,15 +3,15 @@ Notify users of recently added episode to show that they have watched at least L
Also notify users of new movies.
Block users with IGNORE_LST.
Arguments passed from PlexPy
Arguments passed from Tautulli
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type}
-pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -grk {grandparent_rating_key}
You can add more arguments if you want more details in the email body
Adding to PlexPy
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Adding to Tautulli
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on recently added
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Recently Added: notify_fav_tv_all_movie.py
"""
@ -23,8 +23,8 @@ import sys
import argparse
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
IGNORE_LST = ['123456', '123456'] # User_ids
LIMIT = 3
@ -93,52 +93,52 @@ class UserHIS(object):
self.show_key = d['grandparent_rating_key']
def get_get_user(user_id):
# Get the user list from PlexPy.
payload = {'apikey': PLEXPY_APIKEY,
def get_user(user_id):
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': int(user_id)}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
return Users(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_get_users():
# Get the user list from PlexPy.
payload = {'apikey': PLEXPY_APIKEY,
def get_users():
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_users'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
return res_data
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_get_history(showkey):
# Get the user history from PlexPy. Length matters!
payload = {'apikey': PLEXPY_APIKEY,
def get_history(showkey):
# Get the user history from Tautulli. Length matters!
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'grandparent_rating_key': showkey,
'length': 10000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1
and d['media_type'].lower() in ('episode', 'show')]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def add_to_dictlist(d, key, val):
@ -149,7 +149,7 @@ def add_to_dictlist(d, key, val):
def get_email(show):
history = get_get_history(show)
history = get_history(show)
[add_to_dictlist(user_dict, h.user_id, h.show_key) for h in history]
# {user_id1: [grand_key, grand_key], user_id2: [grand_key]}
@ -166,7 +166,7 @@ def get_email(show):
for i in user_lst:
try:
if user_dict[i][show] > LIMIT:
g = get_get_user(i)
g = get_user(i)
if g.user_id not in IGNORE_LST:
sys.stdout.write("Sending {g.user_id} email for %s.".format(g=g) % show)
email_lst += [g.email]
@ -237,7 +237,7 @@ if __name__ == '__main__':
if p.media_type == 'movie':
email_subject = MOVIE_SUBJECT.format(p=p)
to = filter(None, [x['email'] for x in get_get_users() if x['user_id'] not in IGNORE_LST])
to = filter(None, [x['email'] for x in get_users() if x['user_id'] not in IGNORE_LST])
body_html = MOVIE_BODY.format(p=p)
send_email(to, email_subject, body_html)

View File

@ -1,15 +1,16 @@
"""
Pulling together User IP information and Email.
Adding to PlexPy
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Adding to Tautulli
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: notify_newip.py
Arguments passed from PlexPy
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type} -pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -ip {ip_address} -us {user} -uid {user_id} -pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
Arguments passed from Tautulli
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type}
-pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -ip {ip_address} -us {user} -uid {user_id}
-pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
"""
@ -17,11 +18,10 @@ import argparse
import requests
import sys
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
NOTIFICATION_ID = 10 # The notification agent ID for PlexPy 10 = Email
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
NOTIFIER_ID = 12 # The notification notifier ID
# Replace LAN IP addresses that start with the LAN_SUBNET with a WAN IP address
# to retrieve geolocation data. Leave REPLACEMENT_WAN_IP blank for no replacement.
@ -38,16 +38,19 @@ BODY_TEXT = """\
<head></head>
<body>
<p>Hi!<br>
<br><a href="mailto:{u.email}"><img src="{u.user_thumb}" alt="Poster unavailable" height="50" width="50"></a> {p.user} has watched {p.media_type}:{p.title} from a new IP address: {p.ip_address}<br>
<br>On {p.platform}[{p.player}] in <a href="http://maps.google.com/?q={g.city},{g.country},{g.postal_code}">{g.city}, {g.country} {g.postal_code}</a> at {p.timestamp} on {p.datestamp}<br>
<br><a href="mailto:{u.email}"><img src="{u.user_thumb}" alt="Poster unavailable" height="50" width="50"></a>
{p.user} has watched {p.media_type}:{p.title} from a new IP address: {p.ip_address}<br>
<br>On {p.platform}[{p.player}] in
<a href="http://maps.google.com/?q={g.city},{g.country},{g.postal_code}">{g.city}, {g.country} {g.postal_code}</a>
at {p.timestamp} on {p.datestamp}<br>
<br><br>
<br>User email is: {u.email}<br>
</p>
</body>
</html>
"""
##Geo Space##
class GeoData(object):
def __init__(self, data=None):
data = data or {}
@ -55,29 +58,24 @@ class GeoData(object):
self.city = data.get('city', 'N/A')
self.postal_code = data.get('postal_code', 'N/A')
##USER Space##
class UserEmail(object):
def __init__(self, data=None):
data = data or {}
self.email = data.get('email', 'N/A')
self.user_id = data.get('user_id', 'N/A')
self.user_thumb = data.get('user_thumb', 'N/A')
##IP Space##
class UserIPs(object):
def __init__(self, data=None):
data = data or {}
##API Space##
def get_user_ip_addresses(user_id='', ip_address=''):
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user_ips',
'user_id': user_id,
'search': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -88,24 +86,25 @@ def get_user_ip_addresses(user_id='', ip_address=''):
sys.stdout.write("Successfully retrieved UserIPs data.")
if response['response']['data']['recordsFiltered'] == 0:
sys.stdout.write("IP has no history.")
return UserIPs(data=data)
return data
else:
sys.stdout.write("IP has history, killing script.")
exit()
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_user_ip_addresses' request failed: {0}.".format(e))
return UserIPs()
sys.stderr.write("Tautulli API 'get_user_ip_addresses' request failed: {0}.".format(e))
return
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the geo IP lookup from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_geoip_lookup',
'ip_address': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -118,18 +117,18 @@ def get_geoip_info(ip_address=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_geoip_lookup' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_geoip_lookup' request failed: {0}.".format(e))
return GeoData()
def get_user_email(user_id=''):
# Get the user email from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the user email from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': user_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -142,9 +141,10 @@ def get_user_email(user_id=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
return UserEmail()
def send_notification(arguments=None, geodata=None, useremail=None):
# Format notification text
try:
@ -153,27 +153,28 @@ def send_notification(arguments=None, geodata=None, useremail=None):
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': NOTIFICATION_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
if __name__ == '__main__':
# Parse arguments from PlexPy
# Parse arguments from Tautulli
parser = argparse.ArgumentParser()
parser.add_argument('-ip', '--ip_address', action='store', default='',
@ -181,7 +182,7 @@ if __name__ == '__main__':
parser.add_argument('-us', '--user', action='store', default='',
help='Username of the person watching the stream')
parser.add_argument('-uid', '--user_id', action='store', default='',
help='User_ID of the person watching the stream')
help='User_ID of the person watching the stream')
parser.add_argument('-med', '--media_type', action='store', default='',
help='The media type of the stream')
parser.add_argument('-tt', '--title', action='store', default='',
@ -210,7 +211,7 @@ if __name__ == '__main__':
help='The summary of the TV show')
parser.add_argument('-lbn', '--library_name', action='store', default='',
help='The name of the TV show')
p = parser.parse_args()
# Check to make sure there is an IP address before proceeding
@ -219,11 +220,11 @@ if __name__ == '__main__':
ip_address = REPLACEMENT_WAN_IP
else:
ip_address = p.ip_address
g = get_geoip_info(ip_address=ip_address)
u = get_user_email(user_id=p.user_id)
get_user_ip_addresses(user_id=p.user_id, ip_address=p.ip_address)
send_notification(arguments=p, geodata=g, useremail=u)
else:
sys.stdout.write("No IP address passed from PlexPy.")
sys.stdout.write("No IP address passed from Tautulli.")

View File

@ -1,10 +1,10 @@
"""
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on Recently Added
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Recently Added: notify_on_added.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type} -pos {poster_url} -tt {title} -sum {summary} -lbn {library_name}
You can add more arguments if you want more details in the email body
@ -61,7 +61,7 @@ if not too:
to = list([u['email'] for u in users if p.show_name in u['shows']])
# Email settings
name = 'PlexPy' # Your name
name = 'Tautulli' # Your name
sender = 'sender' # From email address
email_server = 'smtp.gmail.com' # Email server (Gmail: smtp.gmail.com)
email_port = 587 # Email port (Gmail: 587)

View File

@ -2,15 +2,15 @@
Notify users of recently added episode to show that they have watched at least LIMIT times via email.
Block users with IGNORE_LST.
Arguments passed from PlexPy
Arguments passed from Tautulli
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type}
-pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -grk {grandparent_rating_key}
You can add more arguments if you want more details in the email body
Adding to PlexPy
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Adding to Tautulli
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on recently added
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Recently Added: notify_user_favorite.py
"""
@ -22,8 +22,8 @@ import sys
import argparse
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
IGNORE_LST = [123456, 123456] # User_ids
LIMIT = 3
@ -57,38 +57,38 @@ class UserHIS(object):
self.show_key = d['grandparent_rating_key']
def get_get_user(user_id):
# Get the user list from PlexPy.
payload = {'apikey': PLEXPY_APIKEY,
def get_user(user_id):
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': int(user_id)}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
return Users(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_get_history(showkey):
# Get the user history from PlexPy. Length matters!
payload = {'apikey': PLEXPY_APIKEY,
def get_history(showkey):
# Get the user history from Tautulli. Length matters!
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'grandparent_rating_key': showkey,
'length': 10000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1
and d['media_type'].lower() in ('episode', 'show')]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def add_to_dictlist(d, key, val):
@ -99,7 +99,7 @@ def add_to_dictlist(d, key, val):
def get_email(show):
history = get_get_history(show)
history = get_history(show)
[add_to_dictlist(user_dict, h.user_id, h.show_key) for h in history]
# {user_id1: [grand_key, grand_key], user_id2: [grand_key]}
@ -116,7 +116,7 @@ def get_email(show):
for i in user_lst:
try:
if user_dict[i][show] >= LIMIT:
g = get_get_user(i)
g = get_user(i)
if g.user_id not in IGNORE_LST:
sys.stdout.write("Sending {g.user_id} email for %s.".format(g=g) % show)
email_lst += [g.email]

View File

@ -1,9 +1,9 @@
"""
Pulling together User IP information and Email.
Enable the API under Settings > Access Control and remember your API key.
Shutdown PlexPy and open your config.ini file in a text editor.
Shutdown Tautulli and open your config.ini file in a text editor.
Set api_sql = 1 in the config file.
Restart PlexPy.
Restart Tautulli.
Place in Playback Start
"""
import argparse
@ -16,8 +16,8 @@ import smtplib
## -sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type} -pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -ip {ip_address} -us {user} -uid {user_id} -pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxxxxxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxxxxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
# Replace LAN IP addresses that start with the LAN_SUBNET with a WAN IP address
# to retrieve geolocation data. Leave REPLACEMENT_WAN_IP blank for no replacement.
@ -72,14 +72,14 @@ class UserEmail(object):
##API Space##
def get_user_ip_addresses(user_id='', ip_address=''):
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user_ips',
'user_id': user_id,
'search': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -97,16 +97,16 @@ def get_user_ip_addresses(user_id='', ip_address=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_user_ip_addresses' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user_ip_addresses' request failed: {0}.".format(e))
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the geo IP lookup from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_geoip_lookup',
'ip_address': ip_address}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -119,18 +119,18 @@ def get_geoip_info(ip_address=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_geoip_lookup' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_geoip_lookup' request failed: {0}.".format(e))
return GeoData()
def get_user_email(user_id=''):
# Get the user email from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Get the user email from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': user_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
@ -143,7 +143,7 @@ def get_user_email(user_id=''):
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
return UserEmail()
def send_notification(arguments=None, geodata=None, useremail=None):
@ -170,17 +170,17 @@ def send_notification(arguments=None, geodata=None, useremail=None):
def clr_sql(ip):
try:
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'sql',
'query': 'DELETE FROM session_history WHERE ip_address = "' + ip + '";'}
requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
except Exception as e:
sys.stderr.write("PlexPy API 'get_sql' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_sql' request failed: {0}.".format(e))
if __name__ == '__main__':
# Parse arguments from PlexPy
# Parse arguments from Tautulli
parser = argparse.ArgumentParser()
parser.add_argument('-ip', '--ip_address', action='store', default='',

View File

@ -3,11 +3,11 @@
pip install requests
pip install twitter
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on Recently Added
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Recently Added: twitter_notify.py
PlexPy > Settings > Notifications > Script > Script Arguments:
Tautulli > Settings > Notifications > Script > Script Arguments:
-sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -dur {duration}
-srv {server_name} -med {media_type} -tt {title} -purl {plex_url} -post {poster_url}

View File

@ -1,5 +1,5 @@
"""
Find when media was added between STARTFRAME and ENDFRAME to Plex through PlexPy.
Find when media was added between STARTFRAME and ENDFRAME to Plex through Tautulli.
Some Exceptions have been commented out to supress what is printed.
Uncomment Exceptions if you run into problem and need to investigate.
@ -22,8 +22,8 @@ LASTMONTH = int(TODAY - 2629743) # 2629743 = 1 month in seconds
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['TV Shows', 'Movies'] # Names of your libraries you want to check.
@ -49,15 +49,15 @@ class METAINFO(object):
self.file_size = d['file_size']
def get_get_new_rating_keys(rating_key, media_type):
def get_new_rating_keys(rating_key, media_type):
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_new_rating_keys',
'rating_key': rating_key,
'media_type': media_type}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
@ -68,35 +68,35 @@ def get_get_new_rating_keys(rating_key, media_type):
return episode_lst
except Exception as e:
#sys.stderr.write("PlexPy API 'get_get_new_rating_keys' request failed: {0}.".format(e))
#sys.stderr.write("Tautulli API 'get_new_rating_keys' request failed: {0}.".format(e))
def get_get_library_media_info(section_id):
# Get the data on the PlexPy media info tables. Length matters!
payload = {'apikey': PLEXPY_APIKEY,
def get_library_media_info(section_id):
# Get the data on the Tautulli media info tables. Length matters!
payload = {'apikey': TAUTULLI_APIKEY,
'section_id': section_id,
'order_dir ': 'asc',
'cmd': 'get_library_media_info',
'length': 10000000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [LIBINFO(data=d) for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['metadata']
@ -104,57 +104,57 @@ def get_get_metadata(rating_key):
return METAINFO(data=res_data)
except Exception as e:
# sys.stderr.write("PlexPy API 'get_get_metadata' request failed: {0}.".format(e))
# sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
def update_library_media_info(section_id):
# Get the data on the PlexPy media info tables.
payload = {'apikey': PLEXPY_APIKEY,
# Get the data on the Tautulli media info tables.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_library_media_info',
'section_id': section_id,
'refresh': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.status_code
if response != 200:
print(r.content)
except Exception as e:
sys.stderr.write("PlexPy API 'update_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'update_library_media_info' request failed: {0}.".format(e))
def get_get_libraries_table():
# Get the data on the PlexPy libraries table.
payload = {'apikey': PLEXPY_APIKEY,
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries_table'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [d['section_id'] for d in res_data if d['section_name'] in LIBRARY_NAMES]
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries_table' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
show_lst = []
count_lst = []
size_lst = []
glt = [lib for lib in get_get_libraries_table()]
glt = [lib for lib in get_libraries_table()]
# Updating media info for libraries.
[update_library_media_info(i) for i in glt]
for i in glt:
try:
gglm = get_get_library_media_info(i)
gglm = get_library_media_info(i)
for x in gglm:
try:
if x.media_type in ['show', 'episode']:
# Need to find TV shows rating_key for episode.
show_lst += get_get_new_rating_keys(x.rating_key, x.media_type)
show_lst += get_new_rating_keys(x.rating_key, x.media_type)
else:
# Find movie rating_key.
show_lst += [int(x.rating_key)]
@ -170,7 +170,7 @@ for i in glt:
for i in sorted(show_lst, reverse=True):
try:
x = get_get_metadata(str(i))
x = get_metadata(str(i))
added = time.ctime(float(x.added_at))
count_lst += [x.media_type]
size_lst += [int(x.file_size)]

View File

@ -1,6 +1,6 @@
# 1. Install the requests module for python.
# pip install requests
# 2. Add script arguments in PlexPy.
# 2. Add script arguments in Tautulli.
# {user} {title}
# Add to Playback Resume
@ -11,11 +11,11 @@ user = sys.argv[1]
title = sys.argv[2]
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
AGENT_ID = 10 # The notification agent ID for PlexPy
TAUTULLI_APIKEY = 'XXXXXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
NOTIFIER_ID = 10 # The notification notifier ID for Tautulli
SUBJECT_TEXT = "PlexPy Notification"
SUBJECT_TEXT = "Tautulli Notification"
BODY_TEXT = """\
<html>
<head></head>
@ -33,22 +33,23 @@ class UserHIS(object):
data = data or {}
self.watched = [d['watched_status'] for d in data]
def get_get_history():
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_history():
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': user,
'search': title}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['data']['recordsFiltered'] > 2:
res_data = response['response']['data']['data']
return UserHIS(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def send_notification():
@ -59,28 +60,28 @@ def send_notification():
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
if __name__ == '__main__':
hisy = get_get_history()
hisy = get_history()
if sum(hisy.watched) == 0:
sys.stdout.write(user + ' has attempted to watch ' + title + ' more than 3 times unsuccessfully.')

View File

@ -8,8 +8,8 @@ import requests
import sys
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
lib_met = []
err_title = []
@ -28,43 +28,43 @@ class UserHIS(object):
self.title = [d['full_title'] for d in data]
def get_get_plex_log():
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_plex_log():
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_plex_log'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return PlexLOG(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_plex_log' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_plex_log' request failed: {0}.".format(e))
def get_get_history(key):
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_history(key):
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'rating_key': key}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return UserHIS(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
if __name__ == '__main__':
p_log = get_get_plex_log()
p_log = get_plex_log()
for co, msg in p_log.error_msg:
lib_met += [(msg.split('/library/metadata/'))[1].split(r'\n')[0]]
for i in lib_met:
his = get_get_history(int(i))
his = get_history(int(i))
err_title += [x.encode('UTF8') for x in his.title]
err_title = ''.join((set(err_title)))
print(err_title + ' is having playback issues')

View File

@ -6,23 +6,23 @@ drive = 'F:'
disk = psutil.disk_partitions()
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
PLEXPY_APIKEY = 'xxxxxx' # Enter your PlexPy API Key
AGENT_LST = [10, 11] # The PlexPy notifier agent id found here: https://github.com/drzoidberg33/plexpy/blob/master/plexpy/notifiers.py#L43
NOTIFY_SUBJECT = 'PlexPy' # The notification subject
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
TAUTULLI_APIKEY = 'xxxxxx' # Enter your Tautulli API Key
NOTIFIER_LST = [10, 11] # The Tautulli notifier notifier id found here: https://github.com/drzoidberg33/plexpy/blob/master/plexpy/notifiers.py#L43
NOTIFY_SUBJECT = 'Tautulli' # The notification subject
NOTIFY_BODY = 'The Plex disk {0} was not found'.format(drive) # The notification body
disk_check = [True for i in disk if drive in i.mountpoint]
if not disk_check:
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'subject': NOTIFY_SUBJECT,
'body': NOTIFY_BODY}
for agent in AGENT_LST:
payload['agent_id'] = agent
requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
for notifier in NOTIFIER_LST:
payload['notifier_id'] = notifier
requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
else:
pass

View File

@ -1,5 +1,5 @@
"""
Use PlexPy to print plays by library from 0, 1, 7, or 30 days ago. 0 = total
Use Tautulli to print plays by library from 0, 1, 7, or 30 days ago. 0 = total
optional arguments:
-h, --help show this help message and exit
@ -28,8 +28,8 @@ import argparse
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
OUTPUT = 'Library: {section}\nDays: {days}\nPlays: {plays}'
@ -37,11 +37,11 @@ OUTPUT = 'Library: {section}\nDays: {days}\nPlays: {plays}'
def get_library_names():
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_library_names'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response, indent=4, sort_keys=True))
@ -49,17 +49,17 @@ def get_library_names():
return [d for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_names' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_names' request failed: {0}.".format(e))
def get_library_watch_time_stats(section_id):
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_library_watch_time_stats',
'section_id': section_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response, indent=4, sort_keys=True))
@ -67,7 +67,7 @@ def get_library_watch_time_stats(section_id):
return [d for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_watch_time_stats' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_watch_time_stats' request failed: {0}.".format(e))
def main():
@ -75,7 +75,7 @@ def main():
lib_lst = [section['section_name'] for section in get_library_names()]
days_lst = [0, 1, 7, 30]
parser = argparse.ArgumentParser(description="Use PlexPy to pull plays by library",
parser = argparse.ArgumentParser(description="Use Tautulli to pull plays by library",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-l', '--libraries', nargs='+', type=str, default=lib_lst, choices=lib_lst, metavar='',
help='Space separated list of case sensitive names to process. Allowed names are: \n'

View File

@ -1,5 +1,5 @@
"""
Use PlexPy to pull plays by library
Use Tautulli to pull plays by library
optional arguments:
-h, --help show this help message and exit
@ -24,8 +24,8 @@ import json
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
OUTPUT = '{section} - Plays: {plays}'
@ -33,12 +33,12 @@ OUTPUT = '{section} - Plays: {plays}'
def get_libraries_table(sections=None):
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries_table',
'order_column': 'plays'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response, indent=4, sort_keys=True))
@ -49,14 +49,14 @@ def get_libraries_table(sections=None):
return [d for d in res_data if d['section_name']]
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries_table' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
def main():
lib_lst = [section['section_name'] for section in get_libraries_table()]
parser = argparse.ArgumentParser(description="Use PlexPy to pull plays by library",
parser = argparse.ArgumentParser(description="Use Tautulli to pull plays by library",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-l', '--libraries', nargs='+', type=str, choices=lib_lst, metavar='',
help='Space separated list of case sensitive names to process. Allowed names are: \n'

View File

@ -1,6 +1,6 @@
"""
Use PlexPy to count how many plays per user occurred this week.
Notify via PlexPy Notification
Use Tautulli to count how many plays per user occurred this week.
Notify via Tautulli Notification
"""
import requests
@ -11,10 +11,10 @@ TODAY = int(time.time())
LASTWEEK = int(TODAY - 7 * 24 * 60 * 60)
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
SUBJECT_TEXT = "PlexPy Weekly Plays Per User"
AGENT_ID = 10 # The email notification agent ID for PlexPy
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
SUBJECT_TEXT = "Tautulli Weekly Plays Per User"
NOTIFIER_ID = 10 # The email notification notifier ID for Tautulli
class UserHIS(object):
@ -29,14 +29,14 @@ class UserHIS(object):
self.full_title = d['full_title']
self.date = d['date']
def get_get_history():
# Get the PlexPy history. Count matters!!!
payload = {'apikey': PLEXPY_APIKEY,
def get_history():
# Get the Tautulli history. Count matters!!!
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'length': 100000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
@ -44,7 +44,7 @@ def get_get_history():
LASTWEEK < d['date'] < TODAY]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def send_notification(BODY_TEXT):
# Format notification text
@ -54,23 +54,23 @@ def send_notification(BODY_TEXT):
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
def add_to_dictlist(d, key, val):
@ -82,7 +82,7 @@ def add_to_dictlist(d, key, val):
user_dict ={}
notify_lst = []
[add_to_dictlist(user_dict, h.user, h.media) for h in get_get_history()]
[add_to_dictlist(user_dict, h.user, h.media) for h in get_history()]
# Get count of media_type play in time frame
for key, value in user_dict.items():
user_dict[key] = {x: value.count(x) for x in value}

View File

@ -5,7 +5,7 @@ Library stats can display total items in Shows, Seasons, Episodes, Artists, Albu
User stats display username and hour, minutes, and seconds of view time
PlexPy Settings > Extra Settings > Check - Calculate Total File Sizes [experimental] ...... wait
Tautulli Settings > Extra Settings > Check - Calculate Total File Sizes [experimental] ...... wait
"""
@ -19,12 +19,12 @@ import argparse
# EDIT THESE SETTINGS #
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
SUBJECT_TEXT = "PlexPy Weekly Server, Library, and User Statistics"
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
SUBJECT_TEXT = "Tautulli Weekly Server, Library, and User Statistics"
# Notification agent ID: https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
AGENT_ID = 10 # The email notification agent ID for PlexPy
# Notification notifier ID: https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
NOTIFIER_ID = 10 # The email notification notifier ID for Tautulli
# Remove library element you do not want shown. Logging before exclusion.
# SHOW_STAT = 'Shows: {0}, Episodes: {2}'
@ -72,15 +72,15 @@ BODY_TEXT = """\
# /EDIT THESE SETTINGS #
def get_get_history(section_id, check_date):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(section_id, check_date):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'section_id': section_id,
'start_date': check_date}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
res_data = response['response']['data']
@ -90,40 +90,40 @@ def get_get_history(section_id, check_date):
pass
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def get_get_libraries():
def get_libraries():
# Get a list of all libraries on your server.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
res_data = response['response']['data']
return res_data
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries' request failed: {0}.".format(e))
def get_get_library_media_info(section_id):
def get_library_media_info(section_id):
# Get a list of all libraries on your server.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_library_media_info',
'section_id': section_id}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
# print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
res_data = response['response']['data']
return res_data['total_file_size']
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def send_notification(body_text):
@ -134,23 +134,23 @@ def send_notification(body_text):
except LookupError as e:
sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
return None
# Send the notification through PlexPy
payload = {'apikey': PLEXPY_APIKEY,
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'notifier_id': NOTIFIER_ID,
'subject': subject,
'body': body}
try:
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
if response['response']['result'] == 'success':
sys.stdout.write("Successfully sent PlexPy notification.")
sys.stdout.write("Successfully sent Tautulli notification.")
else:
raise Exception(response['response']['message'])
except Exception as e:
sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
@ -194,9 +194,9 @@ def get_server_stats(date_ranges):
user_durations_lst =[]
print('Checking library stats.')
for sections in get_get_libraries():
for sections in get_libraries():
lib_size = get_get_library_media_info(sections['section_id'])
lib_size = get_library_media_info(sections['section_id'])
total_size += lib_size
sections_id_lst += [sections['section_id']]
@ -221,7 +221,7 @@ def get_server_stats(date_ranges):
for check_date in date_ranges:
for section_id in sections_id_lst:
# print(check_date, section_id)
history = get_get_history(section_id, check_date)
history = get_history(section_id, check_date)
if history:
# print(json.dumps(history, indent=4, sort_keys=True))
for data in history:
@ -254,7 +254,7 @@ def main():
global BODY_TEXT
parser = argparse.ArgumentParser(description="Use PlexPy to pull library and user statistics for date range.",
parser = argparse.ArgumentParser(description="Use Tautulli to pull library and user statistics for date range.",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-d', '--days', default=7, metavar='', type=int,
help='Enter in number of days to go back. \n(default: %(default)s)')

View File

@ -1,5 +1,5 @@
'''
Use PlexPy to pull last IP address from user and add to List of IP addresses and networks that are allowed without auth in Plex.
Use Tautulli to pull last IP address from user and add to List of IP addresses and networks that are allowed without auth in Plex.
optional arguments:
-h, --help show this help message and exit
@ -22,35 +22,35 @@ import sys
## EDIT THESE SETTINGS ##
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
PLEXPY_APIKEY = 'xxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
def get_get_history(user_id):
# Get the user history from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_history(user_id):
# Get the user history from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user_id': user_id,
'length': 1}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [d['ip_address'] for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def get_get_user_names(username):
# Get the user names from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_user_names(username):
# Get the user names from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user_names'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
if username:
@ -59,7 +59,7 @@ def get_get_user_names(username):
return [d['friendly_name'] for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_user_names' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user_names' request failed: {0}.".format(e))
def add_auth_bypass(net_str):
@ -70,8 +70,8 @@ def add_auth_bypass(net_str):
if __name__ == '__main__':
user_lst = get_get_user_names('')
parser = argparse.ArgumentParser(description="Use PlexPy to pull last IP address from user and add to List of "
user_lst = get_user_names('')
parser = argparse.ArgumentParser(description="Use Tautulli to pull last IP address from user and add to List of "
"IP addresses and networks that are allowed without auth in Plex.",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-u', '--users', nargs='+', type=str, choices=user_lst, metavar='',
@ -89,16 +89,16 @@ if __name__ == '__main__':
elif opts.clear and len(opts.users) == 1:
print('Clearing List of IP addresses and networks that are allowed without auth in Plex.')
add_auth_bypass('')
user_id = get_get_user_names(opts.users)
user_ip = get_get_history(user_id)
user_id = get_user_names(opts.users)
user_ip = get_history(user_id)
print('Adding {} to List of IP addresses and networks that are allowed without auth in Plex.'
.format(''.join(user_ip)))
add_auth_bypass(user_ip)
elif opts.clear and len(opts.users) > 1:
print('Clearing List of IP addresses and networks that are allowed without auth in Plex.')
add_auth_bypass('')
userid_lst = [get_get_user_names(user_names) for user_names in opts.users]
userip_lst = [get_get_history(user_id) for user_id in userid_lst]
userid_lst = [get_user_names(user_names) for user_names in opts.users]
userip_lst = [get_history(user_id) for user_id in userid_lst]
flat_list = [item for sublist in userip_lst for item in sublist]
print('Adding {} to List of IP addresses and networks that are allowed without auth in Plex.'
.format(', '.join(flat_list)))

View File

@ -9,8 +9,8 @@ import os
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
SHOW_LST = [123456, 123456, 123456, 123456] # Show rating keys.
USER_LST = ['Sam', 'Jakie', 'Blacktwin'] # Name of users
@ -30,28 +30,28 @@ class METAINFO(object):
self.grandparent_title = d['grandparent_title']
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['metadata']
return METAINFO(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_metadata' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
pass
def get_get_history(user, show, start, length):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(user, show, start, length):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': user,
'grandparent_rating_key': show,
@ -59,14 +59,14 @@ def get_get_history(user, show, start, length):
'length': length}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
meta_dict = {}
@ -79,13 +79,13 @@ for user in USER_LST:
start = 0
while True:
# Getting all watched history for listed users and shows
history = get_get_history(user, show, start, count)
history = get_history(user, show, start, count)
try:
if all([history]):
start += count
for h in history:
# Getting metadata of what was watched
meta = get_get_metadata(h.rating_key)
meta = get_metadata(h.rating_key)
if not any(d['title'] == meta.title for d in meta_lst):
meta_dict = {
'title': meta.title,

View File

@ -1,6 +1,6 @@
"""
Find what was added TFRAME ago and not watched using PlexPy.
Find what was added TFRAME ago and not watched using Tautulli.
"""
@ -13,8 +13,8 @@ TODAY = time.time()
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'XXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['My TV Shows', 'My Movies'] # Name of libraries you want to check.
@ -42,15 +42,15 @@ class METAINFO(object):
self.file = d['file']
def get_get_new_rating_keys(rating_key, media_type):
def get_new_rating_keys(rating_key, media_type):
# Get a list of new rating keys for the PMS of all of the item's parent/children.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_new_rating_keys',
'rating_key': rating_key,
'media_type': media_type}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']
@ -61,59 +61,59 @@ def get_get_new_rating_keys(rating_key, media_type):
return episode_lst
except Exception as e:
sys.stderr.write("PlexPy API 'get_new_rating_keys' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_new_rating_keys' request failed: {0}.".format(e))
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['metadata']
return METAINFO(data=res_data)
except Exception as e:
# sys.stderr.write("PlexPy API 'get_get_metadata' request failed: {0}.".format(e))
# sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
pass
def get_get_library_media_info(section_id):
# Get the data on the PlexPy media info tables.
payload = {'apikey': PLEXPY_APIKEY,
def get_library_media_info(section_id):
# Get the data on the Tautulli media info tables.
payload = {'apikey': TAUTULLI_APIKEY,
'section_id': section_id,
'cmd': 'get_library_media_info',
'length': 10000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [LIBINFO(data=d) for d in res_data if d['play_count'] is None and (TODAY - int(d['added_at'])) > TFRAME]
except Exception as e:
sys.stderr.write("PlexPy API 'get_library_media_info' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def get_get_libraries_table():
# Get the data on the PlexPy libraries table.
payload = {'apikey': PLEXPY_APIKEY,
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_libraries_table'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [d['section_id'] for d in res_data if d['section_name'] in LIBRARY_NAMES]
except Exception as e:
sys.stderr.write("PlexPy API 'get_libraries_table' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
def delete_files(tmp_lst):
del_file = raw_input('Delete all unwatched files? (yes/no)').lower()
@ -127,16 +127,16 @@ def delete_files(tmp_lst):
show_lst = []
path_lst = []
glt = [lib for lib in get_get_libraries_table()]
glt = [lib for lib in get_libraries_table()]
for i in glt:
try:
gglm = get_get_library_media_info(i)
gglm = get_library_media_info(i)
for x in gglm:
try:
if x.media_type in ['show', 'episode']:
# Need to find TV shows rating_key for episode.
show_lst += get_get_new_rating_keys(x.rating_key, x.media_type)
show_lst += get_new_rating_keys(x.rating_key, x.media_type)
else:
# Find movie rating_key.
show_lst += [int(x.rating_key)]
@ -149,7 +149,7 @@ for i in glt:
# Remove reverse sort if you want the oldest keys first.
for i in sorted(show_lst, reverse=True):
try:
x = get_get_metadata(str(i))
x = get_metadata(str(i))
added = time.ctime(float(x.added_at))
if x.grandparent_title == '' or x.media_type == 'movie':
# Movies

View File

@ -14,7 +14,7 @@ import os
## Edit ##
# Imgur info
CLIENT_ID = 'xxxxx' # PlexPy Settings > Notifications > Imgur Client ID
CLIENT_ID = 'xxxxx' # Tautulli Settings > Notifications > Imgur Client ID
ALBUM_ID = '7JeSw' # http://imgur.com/a/7JeSw <--- 7JeSw is the ablum_id
# Local info

View File

@ -1,11 +1,17 @@
"""
Description: Purge Tautulli users that no longer exist as a friend in Plex
Author: DirtyCajunRice
Requires: requests, plexapi
"""
import requests
from plexapi.myplex import MyPlexAccount
TAUTULLI_BASE_URL = '192.168.1.100:8181'
TAUTULLI_API_KEY = 'asd8a9sd8789asd87f9aasdf'
TAUTULLI_BASE_URL = ''
TAUTULLI_API_KEY = ''
PLEX_USERNAME = 'someuser'
PLEX_PASSWORD = 'somepassword'
PLEX_USERNAME = ''
PLEX_PASSWORD = ''
# Do you want to back up the database before deleting?
BACKUP_DB = True

View File

@ -1,14 +1,14 @@
'''
Refresh the next episode of show once current episode is watched.
Check PlexPy's Watched Percent in PlexPy > Settings > General
Check Tautulli's Watched Percent in Tautulli > Settings > General
1. PlexPy > Settings > Notification Agents > Scripts > Bell icon:
1. Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on watched
2. PlexPy > Settings > Notification Agents > Scripts > Gear icon:
2. Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Enter the "Script folder" where you save the script.
Watched: refresh_next_episode.py
Save
3. PlexPy > Settings > Notifications > Script > Script Arguments:
3. Tautulli > Settings > Notifications > Script > Script Arguments:
{show_name} {episode_num00} {season_num00}
'''

View File

@ -13,8 +13,8 @@ from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8182/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8182/' # Your Tautulli URL
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
@ -34,21 +34,21 @@ today = time.mktime(datetime.datetime.today().timetuple())
def get_users_table():
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_users_table',
'order_column': 'last_seen',
'order_dir': 'asc'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [data for data in res_data if data['last_seen']]
except Exception as e:
print("PlexPy API 'get_history' request failed: {0}.".format(e))
print("Tautulli API 'get_history' request failed: {0}.".format(e))
def unshare(user):

View File

@ -12,8 +12,8 @@ import shutil
## EDIT THESE SETTINGS ##
PLEXPY_APIKEY = 'xxxxxxxx' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'xxxxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['My Movies'] # Whatever your movie libraries are called.
USER_LST = ['Joe', 'Alex'] # Name of users
@ -30,15 +30,15 @@ class METAINFO(object):
self.file = d['file']
def get_get_metadata(rating_key):
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': PLEXPY_APIKEY,
payload = {'apikey': TAUTULLI_APIKEY,
'rating_key': rating_key,
'cmd': 'get_metadata',
'media_info': True}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['metadata']
@ -46,13 +46,13 @@ def get_get_metadata(rating_key):
return METAINFO(data=res_data)
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_metadata' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
pass
def get_get_history(user, start, length):
# Get the PlexPy history.
payload = {'apikey': PLEXPY_APIKEY,
def get_history(user, start, length):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': user,
'media_type': 'movie',
@ -60,14 +60,14 @@ def get_get_history(user, start, length):
'length': length}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1]
except Exception as e:
sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def delete_files(tmp_lst):
@ -88,13 +88,13 @@ for user in USER_LST:
start = 0
while True:
# Getting all watched history for listed users
history = get_get_history(user, start, count)
history = get_history(user, start, count)
try:
if all([history]):
start += count
for h in history:
# Getting metadata of what was watched
movies = get_get_metadata(h.rating_key)
movies = get_metadata(h.rating_key)
if not any(d['title'] == movies.title for d in movie_lst):
movie_dict = {
'title': movies.title,

View File

@ -12,22 +12,22 @@ Caveats:
Effected user will need to refresh browser/app or restart app to reconnect.
User watch record stop when unshare is executed.
If user finishes a movie/show while unshared they will not have that record.
PlexPy will not have that record.
Tautulli will not have that record.
Adding to PlexPy
Adding to Tautulli
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on playback start
[X] Notify on watched
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Playback Start: stream_limiter_ban_email.py
Playback Watched: stream_limiter_ban_email.py
If used in PlexPy:
PlexPy will continue displaying that user is watching after unshare is executed in ACTIVITY.
PlexPy will update after ~5 minutes and no longer display user's stream in ACTIVITY.
PlexPy will think that user has stopped.
If used in Tautulli:
Tautulli will continue displaying that user is watching after unshare is executed in ACTIVITY.
Tautulli will update after ~5 minutes and no longer display user's stream in ACTIVITY.
Tautulli will think that user has stopped.
Create new library with one video.
@ -60,8 +60,8 @@ import smtplib
## EDIT THESE SETTINGS ###
PLEXPY_APIKEY = 'XXXXXX' # Your PlexPy API key
PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
PLEX_TOKEN = "<token>"
SERVER_ID = "XXXXX" # Example: https://i.imgur.com/EjaMTUk.png
@ -127,33 +127,33 @@ class Users(object):
self.user_id = d['user_id']
self.friendly_name = d['friendly_name']
def get_get_user(user_id):
# Get the user list from PlexPy.
payload = {'apikey': PLEXPY_APIKEY,
def get_user(user_id):
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': int(user_id)}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
email = response['response']['data']['email']
friend_name = response['response']['data']['friendly_name']
return [email, friend_name]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_user' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_get_history(user_id, bankey):
# Get the user history from PlexPy. Length matters!
payload = {'apikey': PLEXPY_APIKEY,
def get_history(user_id, bankey):
# Get the user history from Tautulli. Length matters!
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'rating_key': bankey,
'user_id': user_id,
'length': 10000}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
rec_filtered = response['response']['data']['recordsFiltered']
# grow this out how you will
@ -163,7 +163,7 @@ def get_get_history(user_id, bankey):
return 'ban'
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_history' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def share(user_id, ban):
@ -236,19 +236,19 @@ def unshare(user_id):
return
def get_get_activity():
# Get the user IP list from PlexPy
payload = {'apikey': PLEXPY_APIKEY,
def get_activity():
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_activity'}
try:
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['sessions']
return [Activity(data=d) for d in res_data]
except Exception as e:
sys.stderr.write("PlexPy API 'get_get_activity' request failed: {0}.".format(e))
sys.stderr.write("Tautulli API 'get_activity' request failed: {0}.".format(e))
def send_notification(to=None, friendly=None, val_cnt=None, val_tot=None, mess=None):
# Format notification text
@ -274,7 +274,7 @@ def send_notification(to=None, friendly=None, val_cnt=None, val_tot=None, mess=N
if __name__ == "__main__":
activity = get_get_activity()
activity = get_activity()
act_lst = [a.user_id for a in activity]
user_lst = [key for key, value in USER_LIBRARIES.iteritems()]
@ -283,8 +283,8 @@ if __name__ == "__main__":
UNBAN = 0
for i in user_lst:
history = get_get_history(i, BAN_RATING)
mail_add, friendly = get_get_user(i)
history = get_history(i, BAN_RATING)
mail_add, friendly = get_user(i)
try:
if act_lst.count(i) >= LIMIT: