Incorporate waiting to kill paused streams into kill_stream.py

Incorporate the functionality of `wait_kill_paused_notify.py` into 
`kill_stream.py`. A new selector is added of `paused` enabling this 
mode, and adds two additional arguments to control how long to wait for 
paused streams, and how often to check a stream's status. The default 
values are to kill a stream after 20 minutes, checking every 30 seconds.

The Tautulli API is used for all functionality, meaning the `plexapi` 
module is no longer required.
This commit is contained in:
Landon Abney 2018-06-16 23:36:27 -07:00
parent 0ba8e2bda0
commit c03860ec70
No known key found for this signature in database
GPG Key ID: 15320D3C4A506996
2 changed files with 64 additions and 120 deletions

View File

@ -32,6 +32,7 @@ Taultulli > Settings > Notification Agents > New Script > Script Arguments:
Select: Playback Start, Playback Pause Select: Playback Start, Playback Pause
Arguments: --jbop SELECTOR --userId {user_id} --username {username} Arguments: --jbop SELECTOR --userId {user_id} --username {username}
--sessionId {session_id} --notify notifierID --sessionId {session_id} --notify notifierID
--interval 30 --limit 1200
--killMessage Your message here. No quotes. --killMessage Your message here. No quotes.
Save Save
@ -43,6 +44,8 @@ import requests
import argparse import argparse
import sys import sys
import os import os
from time import sleep
from datetime import datetime
TAUTULLI_URL = '' TAUTULLI_URL = ''
TAUTULLI_APIKEY = '' TAUTULLI_APIKEY = ''
@ -64,7 +67,7 @@ if sess.verify is False:
import urllib3 import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
SELECTOR = ['stream', 'allStreams'] SELECTOR = ['stream', 'allStreams', 'paused']
def send_notification(subject_text, body_text, notifier_id): def send_notification(subject_text, body_text, notifier_id):
@ -183,6 +186,59 @@ def terminate_session(session_id, message, notifier=None, username=None):
return None return None
def terminate_long_pause(session_id, message, limit, interval, notify=None):
"""Kills the session if it is paused for longer than <limit> seconds.
Parameters
----------
session_id : str
The session id of the session to monitor.
message : str
The message to use if the stream is terminated.
limit : int
The number of seconds the session is allowed to remain paused before it
is terminated.
interval : int
The amount of time to wait between checks of the session state.
notify : int
Tautulli Notification Agent ID to send a notification to on killing a
stream.
"""
start = datetime.now()
fudgeFactor = 100 # Keep checking this long after the defined limit
pausedTime = 0
checkLimit = limit + interval + fudgeFactor
while pausedTime < checkLimit:
sessions = get_activity()
foundSession = False
for session in sessions:
if session['session_id'] == session_id:
foundSession = True
state = session['state']
if state == 'paused':
now = datetime.now()
diff = now - start
if diff.total_seconds() >= limit:
terminate_session(session_id, message, notify)
sys.exit(0)
else:
sleep(interval)
elif state == 'playing' or state == 'buffering':
sys.stdout.write(
"Session '{}' has resumed, ".format(session_id) +
"stopping monitoring.")
sys.exit(0)
if not foundSession:
sys.stdout.write(
"Session '{}' is no longer active ".format(session_id) +
"on the server, stopping monitoring.")
sys.exit(0)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Killing Plex streams from Tautulli.") description="Killing Plex streams from Tautulli.")
@ -197,6 +253,10 @@ if __name__ == "__main__":
parser.add_argument('--notify', type=int, parser.add_argument('--notify', type=int,
help='Notification Agent ID number to Agent to send ' + help='Notification Agent ID number to Agent to send ' +
'notification.') 'notification.')
parser.add_argument('--limit', type=int, default=(20 * 60), # 20 minutes
help='The time session is allowed to remain paused.')
parser.add_argument('--interval', type=int, default=30,
help='The seconds between paused session checks.')
parser.add_argument('--killMessage', nargs='+', parser.add_argument('--killMessage', nargs='+',
help='Message to send to user whose stream is killed.') help='Message to send to user whose stream is killed.')
@ -213,3 +273,6 @@ if __name__ == "__main__":
streams = get_user_session_ids(opts.userId) streams = get_user_session_ids(opts.userId)
for session_id in streams: for session_id in streams:
terminate_session(session_id, message, opts.notify, opts.username) terminate_session(session_id, message, opts.notify, opts.username)
elif opts.jbop == 'paused':
terminate_long_pause(opts.sessionId, message, opts.limit,
opts.interval, opts.notify)

View File

@ -1,119 +0,0 @@
"""
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)