I’m trying to create a channel plugin that calls an external program, specifically launch a browser window, by clicking on a channel icon. I borrowed this idea from a plugin called Caster. However, with Caster, whilst it does the job, clicking on the icon gives a sub-menu and you have to click on another icon to launch the external program.
My code below also works, but annoyingly in Plex Home Theater it creates two browser windows and the log shows two calls to MainMenu. It also briefly displays a message GetDirectoryFailed…, but it’s too quick to see which one.
In Plex Media Server, clicking on the channel icon only opens one browser window, but on exiting back to PMS I see the message “This channel is not responding”. I’m guessing this is because I don’t return anything from MainMenu.
My questions are - 1. how do I prevent two calls to MainMenu, or if I can’t how to prevent two subprocess calls, 2. Can I return something from MainMenu to prevent the errors. 3. Is there another way to accomplish this?
Many thanks for any assistance.
PREFIX = "/video/mychannel"
NAME = "MyChannel"
ART = 'art-default.jpg'
ICON = 'icon-default.png'
import os, subprocess
def Start():
Plugin.AddPrefixHandler(PREFIX, MainMenu, NAME, ICON, ART)
def MainMenu():
Log.Info('Running Application: "' + str(Prefs['app_loc_key']) + '", with the following arguments "' + ClearNoneString(Prefs['app_cl_params_key']) + '"')
subprocess.Popen([str(Prefs['app_loc_key']), ClearNoneString(Prefs['app_cl_params_key'])])
def ClearNoneString(value):
if((value is None) or (value is '[None]')):
return ''
return value
Know that it’s the server that is creating the subprocess, so if you ran it from a remote client you would just be launching browser windows on the server. This is only useful for a PHT client that just happens to be running on the same computer as the server.
You will probably want to store the pid of the subprocess, and only call Popen if the stored pid isn’t running. This would prevent multiple processes being started. PHT has a tendency to call stuff multiple times and be weird.
proc = subprocess.Popen(...)
Dict['pid'] = proc.pid
Dict.Save()
then since you have the pid you can kill it when stuff goes wrong os.kill(Dict['pid'], signal.SIGINT).
You can return empty containers to keep PHT happy. return ObjectContainer() or if it doesn’t like that, you can add a random object to a container and return that.
Thanks for your help, I’ll give those a try. One problem though, how to know when to remove the dictionary entry on closing the browser, so the next time the channel is clicked it will open a new one? Is there a method of os to determine if pid is running? Are there any docs for os?
there are some examples of checking a pid here http://stackoverflow.com/questions/568271/how-to-check-if-there-exists-a-process-with-a-given-pid
so you can check if the current stored pid is running. if it isn’t, do a Popen and save a new pid.
I don’t think this technique is going to work because of concurrency issues. The two calls to MainMenu happen at the same time, so the second check for a running pid takes place before the first has chance to store its pid in the dictionary.
Also, returning an empty ObjectContainer displays a message “No videos matching filters”. Returning an empty DictionaryObject results in an empty list, ok no error, but hardly user friendly. Ideally I would want the Channel List to remain displayed.
This is kind of a deal breaker for me because I want a solution to watch all my entertainment sources whether on my computer or online.
Maybe there’s a simpler way to do this, but I’m not finding it so far.