Skip to content

Instantly share code, notes, and snippets.

@blacktwin
Last active July 22, 2018 20:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blacktwin/88fce565c8ecf56839641f22f4c5c422 to your computer and use it in GitHub Desktop.
Save blacktwin/88fce565c8ecf56839641f22f4c5c422 to your computer and use it in GitHub Desktop.
If user has 2* or more concurrent streams kill all streams
"""
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.
PlexPy > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on user concurrent streams
PlexPy > Settings > Notification Agents > Scripts > Gear icon:
Playback User Concurrent Streams: kill_more_than.py
PlexPy > Settings > Notifications > Script > Script Arguments
{user}
"""
import requests
import platform
from uuid import getnode
import sys
import unicodedata
## EDIT THESE SETTINGS ##
PLEX_HOST = ''
PLEX_PORT = 32400
PLEX_SSL = '' # s or ''
PLEX_TOKEN = 'xxxxxxx'
REASON = 'Because....too many streams'
# 2nd stream information is passed
USER = sys.argv[1]
ignore_lst = ('')
if USER in ignore_lst:
print(u"{} ignored.".format(USER))
exit()
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):
headers = {'X-Plex-Token': PLEX_TOKEN}
params = {'sessionId': sessionId,
'reason': message}
requests.get('http://{}:{}/status/sessions/terminate'.format(PLEX_HOST, PLEX_PORT),
headers=headers, params=params)
response = fetch('status/sessions')
sessions = []
for s in response['MediaContainer']['Video']:
if s['User']['title'] == USER:
id = s['Session']['id']
user = s['User']['title']
title = (s['grandparentTitle'] + ' - ' if s['type'] == 'episode' else '') + s['title']
title = unicodedata.normalize('NFKD', title).encode('ascii','ignore')
sessions.append((id, user, title))
for session in sessions:
print(u"Killing {}'s second stream of {} for {}".format(session[1], session[2], REASON))
kill_stream(session[0], REASON)
@Tangogr
Copy link

Tangogr commented Jul 10, 2017

Great code! Is there a way to add some "timeout"? Sometimes, when user uses cast from android to chromecast, there is a time that plexpy says there are 2 streams.

@Tangogr
Copy link

Tangogr commented Jul 10, 2017

Well, I think I have some UTF-8 issues:

Traceback (most recent call last): 
        File "/var/SERVIDOR/plexpy-killstreams.py", line 88, in 
            print(u"Killing {}'s second stream of {} for {}".format(session[1], session[2], REASON)) 
    UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 72: ordinal not in range(128)

And it is the "ó" letter. Where a f*** is that letter?

I´ve tried to add:

reload(sys)
sys.setdefaultencoding('utf-8')

And I get different error:

Uncaught exception: Traceback (most recent call last):
    File "/var/PLEXPY/logger.py", line 270, in new_run 
        old_run(*args, **kwargs) 
    File "/usr/lib64/python2.7/threading.py", line 764, in run 
        self.__target(*self.__args, **self.__kwargs) 
    File "/var/plexpy/notifiers.py", line 2234, in run_script 
        logger.debug(u"PlexPy Notifiers :: Script returned: \n %s" % out) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 220: ordinal not in range(128) 

The user or the movie has NO strange characters (but my server is Spanish).

UPDATE:

The user causing multiple streams is called "RoboRo", so no "ó" character on it. The movie was "Star Trek - Puerto" (the new generation".

I replaced:

print(u"Killing {}'s second stream of {} for {}".format(session[1], session[2], REASON))
with
print(u"Killing".format(session[1], session[2], REASON))

Now, there is no error, "killing" appears in plexpy logs, but stream is not killed!

Any clue?

@cristianfd
Copy link

cristianfd commented Jul 10, 2017

Try to replicate the problem with curl or another curl-like app like "Advanced Rest Client for Chrome".
Then construct the request replacing the params:

headers = {'X-Plex-Token': PLEX_TOKEN}
  params = {'sessionId': sessionId,
  'reason': message}
  requests.get('http://{}:{}/status/sessions/terminate'.format(PLEX_HOST, PLEX_PORT),
  headers=headers, params=params)

@blacktwin
Copy link
Author

@Tangogr I've updated to hopefully resolve your issue.

@Tangogr
Copy link

Tangogr commented Jul 15, 2017

Thanks for your help @blacktwin but doesn´t work:

2017-07-15 11:00:15 | INFO | PlexPy Notifiers :: Script notification sent.
-- | -- | --
2017-07-15 11:00:15 | DEBUG | PlexPy Notifiers :: Script returned:     Killing RoboRo's second stream of Pixar Short Films Collection Vol 2 - Episode 1 for Too many connections     
Killing RoboRo's second stream of El Mentalista - John el Rojo for Too many connections
2017-07-15 11:00:15 | DEBUG | PlexPy Notifiers :: Executing script in a new thread.
2017-07-15 11:00:15 | DEBUG | PlexPy Notifiers :: Full script is: ['python', u'/var/scripts/plexpy-killstreams.py', u'RoboRo']
2017-07-15 11:00:15 | DEBUG | PlexPy Notifiers :: Trying to run notify script, action: concurrent, arguments: [u'RoboRo']

Logs says everithing is ok, but the two streams are still playing.

@blacktwin
Copy link
Author

@Tangogr just tested it and it works for me. I'm not sure what the hang up is on your end. PlexPy can be somewhat slow to update the stream information, so it may display that it's still playing for a minute. Also I believe this feature is for Plex Pass only. Though I would assume if you don't have a Plex Pass then it would error out.

@Tangogr
Copy link

Tangogr commented Jul 19, 2017

Ohhh, ok, maybe is for plex pass users, and I am not... I´ll test again and will report, THANKS for your help!

@Tangogr
Copy link

Tangogr commented Sep 4, 2017

Well... this is definitely for plex pass users. :-(

@sbcrumb
Copy link

sbcrumb commented Jan 4, 2018

trying to get this to run and getting the following error.
Traceback (most recent call last):
File "kill_all_more_than.py", line 31, in
USERNAME = sys.argv[1]
IndexError: list index out of range

@blacktwin
Copy link
Author

@sbcrumb Please check the updated version of this script in my repo. If you have any problems please use the Issue section to report your problem. I don't get notifications from Gist comments.

@kalyway
Copy link

kalyway commented Mar 24, 2018

I know this is not the current one, which I am using and is working great, but is there a way to kill a users 2nd stream even if it is on the same IP address? I ask because when I am watching something on my same network it doesn't kill the other stream cause it lists the same IP. Would be nice to just kill any stream past 1. Thanks!

@aj843
Copy link

aj843 commented Apr 6, 2018

Bump! would be great if you could make this work for all users!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment