diff --git a/killstream/create_wait_kill_all.py b/killstream/create_wait_kill_all.py index 5e883e0..c1a5a46 100644 --- a/killstream/create_wait_kill_all.py +++ b/killstream/create_wait_kill_all.py @@ -124,12 +124,12 @@ def kill_stream(sessionId, message, xtime, ntime, user, title, sessionKey): def find_sessionID(response): sessions = [] - for s in response['MediaContainer']['Video']: - if s['sessionKey'] == sys.argv[1]: - sess_id = s['Session']['id'] - user = s['User']['title'] - sess_key = s['sessionKey'] - title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title'] + 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: @@ -151,11 +151,13 @@ if __name__ == '__main__': 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' \ @@ -174,10 +176,10 @@ if __name__ == '__main__': 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: + with open(full_path, "w+") as output: output.write(file) - subprocess.Popen([sys.executable, file_name], startupinfo=startupinfo) + subprocess.Popen([sys.executable, full_path], startupinfo=startupinfo) exit(0) except TypeError as e: diff --git a/killstream/create_wait_kill_trans.py b/killstream/create_wait_kill_trans.py new file mode 100644 index 0000000..fd314b5 --- /dev/null +++ b/killstream/create_wait_kill_trans.py @@ -0,0 +1,169 @@ +''' +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']: + if video['sessionKey'] == sessionKey: + if xtime == ntime and video['Player']['state'] == 'paused' and video['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_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']: + if video['sessionKey'] == sys.argv[1] and video['Player']['state'] == 'paused' \ + and video['Media']['Part']['decision'] == 'transcode': + sess_id = video['Session']['id'] + user = video['User']['title'] + sess_key = sys.argv[1] + 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 = 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 diff --git a/killstream/kill_all_more_than.py b/killstream/kill_all_more_than.py index 43cb153..2600afa 100644 --- a/killstream/kill_all_more_than.py +++ b/killstream/kill_all_more_than.py @@ -12,7 +12,7 @@ PlexPy > Settings > Notification Agents > Scripts > Gear icon: Playback User Concurrent Streams: kill_more_than.py PlexPy > Settings > Notifications > Script > Script Arguments - {user} + {username} """ @@ -31,12 +31,12 @@ PLEX_TOKEN = 'xxxxxxx' REASON = 'Because....too many streams' # 2nd stream information is passed -USER = sys.argv[1] +USERNAME = sys.argv[1] ignore_lst = ('') -if USER in ignore_lst: - print(u"{} ignored.".format(USER)) +if USERNAME in ignore_lst: + print(u"{} ignored.".format(USERNAME)) exit() @@ -82,7 +82,7 @@ response = fetch('status/sessions') sessions = [] for s in response['MediaContainer']['Video']: - if s['User']['title'] == USER: + if s['User']['title'] == USERNAME: sess_id = s['Session']['id'] user = s['User']['title'] title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title'] diff --git a/killstream/kill_else_if_buffering.py b/killstream/kill_else_if_buffering.py index 8b2cfe0..0c274db 100644 --- a/killstream/kill_else_if_buffering.py +++ b/killstream/kill_else_if_buffering.py @@ -84,19 +84,19 @@ if __name__ == '__main__': sessions = [] if 'Video' in response['MediaContainer']: - for s in response['MediaContainer']['Video']: + for video in response['MediaContainer']['Video']: try: - if s['TranscodeSession']['videoDecision'] == 'transcode' and s['User']['title'] not in ADMIN_USER: - sess_id = s['Session']['id'] - user = s['User']['title'] - percent_comp = int((float(s['viewOffset']) / float(s['duration'])) * 100) - time_to_comp = int(int(s['duration']) - int(s['viewOffset'])) / 1000 / 60 - title = s['title'] + if video['TranscodeSession']['videoDecision'] == 'transcode' and video['User']['title'] not in ADMIN_USER: + sess_id = video['Session']['id'] + user = video['User']['title'] + percent_comp = int((float(video['viewOffset']) / float(video['duration'])) * 100) + time_to_comp = int(int(video['duration']) - int(video['viewOffset'])) / 1000 / 60 + title = video['title'] title = unicodedata.normalize('NFKD', title).encode('ascii','ignore') add_to_dictlist(user_dict, user, [sess_id, percent_comp, title, user, time_to_comp]) except KeyError: - print('{} has a direct stream to ignore.'.format(s['User']['title'])) + print('{} has a direct stream to ignore.'.format(video['User']['title'])) # Remove users with only 1 stream. Targeting users with multiple concurrent streams filtered_dict = {key: value for key, value in user_dict.items() diff --git a/killstream/kill_more_than.py b/killstream/kill_more_than.py index 4aff68b..4a29685 100644 --- a/killstream/kill_more_than.py +++ b/killstream/kill_more_than.py @@ -32,13 +32,13 @@ PLEX_TOKEN = 'xxxxxxx' REASON = 'Because....too many streams' # 2nd stream information is passed -USER = sys.argv[1] +USERNAME = sys.argv[1] ADDRESS = sys.argv[2] ignore_lst = ('') -if USER in ignore_lst: - print(u"{} ignored.".format(USER)) +if USERNAME in ignore_lst: + print(u"{} ignored.".format(USERNAME)) exit() @@ -83,11 +83,11 @@ def kill_stream(sessionId, message): response = fetch('status/sessions') sessions = [] -for s in response['MediaContainer']['Video']: - if s['User']['title'] == USER and s['Player']['address'].lstrip("::ffff:") == ADDRESS:: - sess_id = s['Session']['id'] - user = s['User']['title'] - title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title'] +for video in response['MediaContainer']['Video']: + if video['User']['title'] == USERNAME and video['Player']['address'].lstrip("::ffff:") == ADDRESS:: + sess_id = video['Session']['id'] + user = video['User']['title'] + title = (video['grandparentTitle'] + ' - ' if video['type'] == 'episode' else '') + video['title'] title = unicodedata.normalize('NFKD', title).encode('ascii','ignore') sessions.append((sess_id, user, title)) diff --git a/killstream/kill_outsider_stream.py b/killstream/kill_outsider_stream.py index 4d1aafe..09aa186 100644 --- a/killstream/kill_outsider_stream.py +++ b/killstream/kill_outsider_stream.py @@ -65,7 +65,7 @@ def kill_stream(sessionId, message): headers=headers, params=params) response = fetch('status/sessions') -for s in response['MediaContainer']['Video']: - if s['User']['title'] == USERNAME and s['Session']['location'] == 'wan': +for video in response['MediaContainer']['Video']: + if video['User']['title'] == USERNAME and video['Session']['location'] == 'wan': print("Killing {}'s stream for {}".format(USERNAME, REASON)) - kill_stream(s['Session']['id'], REASON) + kill_stream(video['Session']['id'], REASON) diff --git a/killstream/kill_plex_stream.py b/killstream/kill_plex_stream.py index d7491c9..5931e0d 100644 --- a/killstream/kill_plex_stream.py +++ b/killstream/kill_plex_stream.py @@ -59,10 +59,10 @@ def kill_stream(sessionId, message): response = fetch('status/sessions') sessions = [] -for s in response['MediaContainer']['Video']: - sess_id = s['Session']['id'] - user = s['User']['title'] - title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title'] +for video in response['MediaContainer']['Video']: + sess_id = video['Session']['id'] + user = video['User']['title'] + title = (video['grandparentTitle'] + ' - ' if video['type'] == 'episode' else '') + video['title'] title = unicodedata.normalize('NFKD', title).encode('ascii','ignore') sessions.append((sess_id, user, title)) diff --git a/killstream/kill_session_bitrate.py b/killstream/kill_session_bitrate.py index b5242c0..f063ce0 100644 --- a/killstream/kill_session_bitrate.py +++ b/killstream/kill_session_bitrate.py @@ -66,12 +66,12 @@ def kill_stream(sessionId, message): response = fetch('status/sessions') sessions = [] -for s in response['MediaContainer']['Video']: - sess_id = s['Session']['id'] - user = s['User']['title'] - title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title'] +for video in response['MediaContainer']['Video']: + sess_id = video['Session']['id'] + user = video['User']['title'] + title = (video['grandparentTitle'] + ' - ' if video['type'] == 'episode' else '') + video['title'] title = unicodedata.normalize('NFKD', title).encode('ascii','ignore') - bitrate = s['Media']['bitrate'] + bitrate = video['Media']['bitrate'] sessions.append((sess_id, user, title, bitrate)) for session in sessions: diff --git a/killstream/kill_trans_exp_audio.py b/killstream/kill_trans_exp_audio.py index 2f9cae2..d5aaab5 100644 --- a/killstream/kill_trans_exp_audio.py +++ b/killstream/kill_trans_exp_audio.py @@ -75,14 +75,14 @@ if __name__ == '__main__': response = fetch('status/sessions') if 'Video' in response['MediaContainer']: - for s in response['MediaContainer']['Video']: - if s['TranscodeSession']['videoDecision'] == 'transcode' and s['User']['title'] not in USER_IGNORE: - MESSAGE = DEVICES.get(s['Player']['platform'], DEFAULT_REASON) - print("Killing {}'s stream for transcoding video".format(s['User']['title'])) - kill_stream(s['Session']['id'], MESSAGE) + for video in response['MediaContainer']['Video']: + if video['TranscodeSession']['videoDecision'] == 'transcode' and video['User']['title'] not in USER_IGNORE: + MESSAGE = DEVICES.get(video['Player']['platform'], DEFAULT_REASON) + print("Killing {}'s stream for transcoding video".format(video['User']['title'])) + kill_stream(video['Session']['id'], MESSAGE) elif 'Track' in response['MediaContainer']: - for s in response['MediaContainer']['Track']: - print("{} is streaming audio, let them pass!".format(s['User']['title'])) + for track in response['MediaContainer']['Track']: + print("{} is streaming audio, let them pass!".format(track['User']['title'])) exit() else: exit() diff --git a/killstream/kill_trans_pause.py b/killstream/kill_trans_pause.py index 809b55b..5d8eede 100644 --- a/killstream/kill_trans_pause.py +++ b/killstream/kill_trans_pause.py @@ -65,11 +65,11 @@ if __name__ == '__main__': response = fetch('status/sessions') try: - for s in response['MediaContainer']['Video']: - if s['TranscodeSession']['videoDecision'] == 'transcode' and s['User']['title'] not in USER_IGNORE \ - and s['Player']['state'] == 'paused': - print("Killing {}'s stream for pausing a transcode stream of {}".format(s['User']['title'], s['title'])) - kill_stream(s['Session']['id'], MESSAGE) + for video in response['MediaContainer']['Video']: + if video['TranscodeSession']['videoDecision'] == 'transcode' and video['User']['title'] not in USER_IGNORE \ + and video['Player']['state'] == 'paused': + print("Killing {}'s stream for pausing a transcode stream of {}".format(video['User']['title'], s['title'])) + kill_stream(video['Session']['id'], MESSAGE) except Exception as e: print('Session error: {}'.format(e)) pass