commit
f38a7f9284
12
.idea/inspectionProfiles/Project_Default.xml
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N803" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
83
README.md
83
README.md
@ -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.
|
||||
Updating for Tautulli
|
||||
|
||||
## 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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
@ -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
|
@ -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.")
|
@ -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
|
||||
|
||||
|
||||
|
@ -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}
|
||||
"""
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
||||
'''
|
||||
|
@ -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}
|
||||
"""
|
||||
|
||||
|
@ -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}
|
||||
"""
|
||||
|
||||
|
@ -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
|
||||
|
||||
"""
|
||||
|
@ -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()
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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}
|
||||
|
||||
"""
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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']:
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
119
killstream/wait_kill_paused_notify.py
Normal file
119
killstream/wait_kill_paused_notify.py
Normal 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)
|
@ -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)
|
||||
|
@ -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.
|
||||
@ -59,12 +57,12 @@ SERVER_PLATFORM = 'Server'
|
||||
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
|
||||
'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:
|
||||
@ -202,7 +205,7 @@ 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})
|
||||
'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,6 +259,7 @@ def get_geojson_dict(user_locations):
|
||||
"features": locs
|
||||
}
|
||||
|
||||
|
||||
def draw_map(map_type, geo_dict, filename, headless):
|
||||
import matplotlib as mpl
|
||||
if headless:
|
||||
@ -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,
|
||||
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(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)
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
|
||||
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
|
||||
@ -11,13 +12,12 @@ import time
|
||||
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,129 +65,127 @@ 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)
|
||||
|
||||
|
||||
BODY_TEXT = """\
|
||||
<html>
|
||||
if notify_lst:
|
||||
BODY_TEXT = """\
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>Hi!<br>
|
||||
@ -195,7 +195,11 @@ BODY_TEXT = """\
|
||||
</dl>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
""".format(notify_lst="\n".join(notify_lst).encode("utf-8"),LIBRARY_NAMES=" & ".join(LIBRARY_NAMES))
|
||||
</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()
|
||||
|
@ -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'])]
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,8 +38,11 @@ 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>
|
||||
@ -47,7 +50,7 @@ BODY_TEXT = """\
|
||||
</html>
|
||||
"""
|
||||
|
||||
##Geo Space##
|
||||
|
||||
class GeoData(object):
|
||||
def __init__(self, data=None):
|
||||
data = data or {}
|
||||
@ -55,7 +58,7 @@ 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 {}
|
||||
@ -63,21 +66,16 @@ class UserEmail(object):
|
||||
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='',
|
||||
@ -226,4 +227,4 @@ if __name__ == '__main__':
|
||||
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.")
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
@ -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='',
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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.')
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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}
|
||||
|
@ -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)')
|
||||
|
40
scriptHeaderTemplate.txt
Normal file
40
scriptHeaderTemplate.txt
Normal file
@ -0,0 +1,40 @@
|
||||
"""
|
||||
Description: {description}
|
||||
Author: {author}
|
||||
Requires: {requirements}
|
||||
|
||||
Enabling Scripts in Tautulli:
|
||||
Taultulli > Settings > Notification Agents > Add a Notification Agent > Script
|
||||
|
||||
Configuration:
|
||||
Taultulli > Settings > Notification Agents > New Script > Configuration:
|
||||
|
||||
Script Name: {script_name}
|
||||
Set Script Timeout: {timeout}
|
||||
Description: {Tautulli_description}
|
||||
Save
|
||||
|
||||
Triggers:
|
||||
Taultulli > Settings > Notification Agents > New Script > Triggers:
|
||||
|
||||
Check: {trigger}
|
||||
Save
|
||||
|
||||
Conditions:
|
||||
Taultulli > Settings > Notification Agents > New Script > Conditions:
|
||||
|
||||
Set Conditions: [{condition} | {operator} | {value} ]
|
||||
Save
|
||||
|
||||
Script Arguments:
|
||||
Taultulli > Settings > Notification Agents > New Script > Script Arguments:
|
||||
|
||||
Select: {trigger}
|
||||
Arguments: {arguments}
|
||||
|
||||
Save
|
||||
Close
|
||||
|
||||
Example:
|
||||
|
||||
"""
|
@ -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)))
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
||||
'''
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user