Last active
October 17, 2019 04:13
-
-
Save blacktwin/2148bb0b2f8d67b8a08c50ace62ad39f to your computer and use it in GitHub Desktop.
Receive session_key from PlexPy when paused. Use session_id to create sub-script to wait for X time then check if transcoding still paused. If so, kill.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
kill_transcode 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 = 'xxx' | |
TIMEOUT = 30 | |
INTERVAL = 10 | |
REASON = 'Because....' | |
ignore_lst = ('test') | |
def fetch(path, t='GET'): | |
url = 'http%s://%s:%s/' % (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 a in response['MediaContainer']['Video']: | |
if a['sessionKey'] == sessionKey: | |
if xtime == ntime and a['Player']['state'] == 'paused' and a['Media']['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_HOST, PLEX_PORT), | |
headers=headers, params=params) | |
return ntime | |
elif a['Player']['state'] in ('playing', 'buffering'): | |
sys.stdout.write("{user}'s stream of {title} is now {state}". | |
format(user=user, title=title, state=a['Player']['state'])) | |
return None | |
else: | |
return xtime | |
else: | |
return None | |
def find_sessionID(response): | |
sessions = [] | |
for s in response['MediaContainer']['Video']: | |
if s['sessionKey'] == sys.argv[1] and s['Player']['state'] == 'paused' \ | |
and s['Media']['Part']['decision'] == 'transcode': | |
sess_id = s['Session']['id'] | |
user = s['User']['title'] | |
sess_key = sys.argv[1] | |
title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['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') | |
try: | |
if find_sessionID(response): | |
stream_info = find_sessionID(response) | |
file_name = "{}.py".format(stream_info[0]) | |
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(file_name, "w+") as output: | |
output.write(file) | |
subprocess.Popen([sys.executable, file_name], startupinfo=startupinfo) | |
exit(0) | |
except TypeError as e: | |
print(e) | |
pass |
@csy7550 If you want, you can try this script. It is kinda the same as this one but set to kill all paused streams and uses PlexPy's Activity to check the stream instead of the xml. Just change line 111 from:
if a.state == 'paused' and xtime == ntime:
to if a.state == 'paused' and a.video_decision == 'transcode' and xtime == ntime:
to include the check for transcoding. Again, that way you're relying on PlexPy definition instead of my definition based on the xml.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@blacktwin Well, it works :-) but an exception for direct streams would be great.. no reason for killing direct streams :-)