I'm using Plex and trying to use the Plex api to get and continually update the status of my Plex Server. If the status changes, I have a couple of things that it does. Here's my code (I've redacted the irrelevant portions):
import requests
import time
ip = '127.0.0.1'
port = '####'
def get_status(last_media_type, last_state):
data = requests.get('http://' + ip + ':' + port + '/status/sessions', verify=False)
if home: # Ignore this part. Redacted code
if '<MediaContainer size="0">' in data.text: # If nothing is playing
media_type = 'None'
state = 'STOPPED'
else: # Get what's playing and its status
media_type_start = data.text.find('type=\"')
media_type_end = data.text.find('updatedAt=')
media_type = data.text[media_type_start + 6:media_type_end - 2].capitalize()
print('Type: ' + str(media_type))
state_prefix_start = data.text.find('<Player address=')
state_prefix_end = data.text.find('<TranscodeSession key=')
state_prefix = data.text[state_prefix_start:state_prefix_end]
state_start = state_prefix.find('state=\"')
state_end = state_prefix.find('title=')
state = state_prefix[state_start + 7:state_end - 2].upper()
if last_media_type != media_type or last_state != state: # THIS IS IMPORTANT. I don't want to execute the next part if nothing has changed.
# DO STUFF, redacted
if state == 'PLAYING':
interval = 1
elif state == 'PAUSED':
interval = 10
elif state == 'STOPPED':
interval = 15
else:
interval = 60 * 3 # if nobody home, only check once every 3 minutes
time.sleep(interval)
get_status(media_type, state)
get_status('a', 'b') # filler arguments used to initiate script
The Problem
Unfortunately, after half an hour or so, I get:
RecursionError: maximum recursion depth exceeded in comparison
This is the traceback (although the line numbers won't match due to redaction):
Traceback (most recent call last):
File "H:/Users/micha/Documents/Scripts/Python/plexStatus.pyw", line 63, in <module>
p = psutil.Process(os.getpid()) # Get PID for this script
File "C:\Python351\lib\site-packages\psutil\__init__.py", line 349, in __init__
self._init(pid)
File "C:\Python351\lib\site-packages\psutil\__init__.py", line 375, in _init
self.create_time()
File "C:\Python351\lib\site-packages\psutil\__init__.py", line 636, in create_time
self._create_time = self._proc.create_time()
File "C:\Python351\lib\site-packages\psutil\_pswindows.py", line 282, in wrapper
return fun(self, *args, **kwargs)
File "C:\Python351\lib\site-packages\psutil\_pswindows.py", line 422, in create_time
if self.pid in (0, 4):
RecursionError: maximum recursion depth exceeded in comparison
The Questions
How can I get this to work without the recursion error while still only waiting 1 second between executions?
My guess is that there's a better way to call this script, while still being able to use the variables from the previous call. I just can't figure out how. I think I can use pickle
which I'm already using in another redacted part, but I'd like to avoid a ton of read/writes if possible. Or really, just make this as little of a memory hog as possible while still retaining functionality.
Notes: I'm sure there's a better way to parse. I'm new to programming. Researching that concurrently as I fix this.
I've edited this code a few times while trying to fix this, so I'm not sure this won't throw up some other error. It's the recursion I'm trying to fix.
I know there are tools like PlexPy for this. Just trying to write one myself that is smaller and I can run continuously without being a major resource hog.
Recursion means that each function call stays on the stack, hence you eventually will run out of memory leading to the RecursionError
. In other There are ways around this using "tail-call recursion", almost like you've done - except Python will never support this.
The best way to run this is to modify your code to have an infinite loop:
def get_status(last_media_type, last_state):
pass # your method here
# except for the recursive call
return state, media_type
last_state = None
last_media_type = 'sensible_default'
while True:
state, media_type = get_status(last_media_type, last_state)
pass # do what you need to compare them here
if last_state != state and last_media_type != media_type:
print "they aren't equal!"
last_state, last_media_type = state, media_type
The loop itself (while True:
) will consume practically no memory, and now instead of storing every single past state, you just have the last one.
Additionally, any information in the method call is garbage collected as it loses scope when your method returns - this is a direct improvement over your code, as in the recursive call nothing ever loses scope so nothing cal ever be collected.