I have an odd question that I am not sure if there is an answer for and hopefully I can explain it properly to where you can understand what I am trying to do.
I am trying to clean up some code in a channel. Most of my channel works, but I have a few exceptions that I would like to keep separated and I am not sure how to do it or if I can.
What I wanted to do was have my final function that produced the actual videos contain all the working code and at the end of the function say if the object container was still empty, send it to another function to try to populate the object container. I cannot figure out how to do this. Is it even possible?
def Videos(arg):
oc = ObjectContainer()
# do stuff
if len(oc) > 0:
return oc
else:
return AlternateVideos(arg)
def AlternateVideos(arg):
oc = ObjectContainer()
# do stuff
return oc
I tried some code that was so close to what you have above, only I forgot to add the return to the front of calling the alternative function. Thanks so much.
I want to create a data file that I then use to populate my main menu. But I am not sure where to even start to look for instructions or examples of other channels that do this.
I am creating a channel that pulls some of my favorite webisodes, but for now, I have all of the shows hardcoded in my main menu. I would like to have a file that contains data for each show so I do not have to edit my channel every time I add a new show. I am thinking a json file would work best.
I know Plex is very particular about what files you have in your channel, so can you pull data from a local json file into your channel. I know you can create a defaultprefs.json that is recognized by Plex. Would that work for this purpose?
And one more question. Let's say you have a channel with limited distribution or your channel is still in test phase so you didn't submit it for inclusion in the Plex channels. But you would still like to make the users aware when you have made changes and updates are available. What is the best method to do this? I have seen channels in the unsupported appstore that have an update button that appears locally in your channel. Is it possible to automate the process directly from Github or do you have to be accepted and listed in the unsupported appstore for this to work. Also, if it is possible, where would I find info on how that works?
Loading data from a bundled file is relatively straightforward. That's actually how the Unsupported Appstore manages the list of available plugins. There's a json file stored in the plugin's "Resources" directory alongside the icons and artwork. Then the data is loaded in the plugin via the Resource.Load('file_name.json') and JSON.ObjectFromString(json_variable_name) commands, as you can see here. Alternatively, you could host a separate json file on the web, either on a private server or service like dropbox and just use a static link in the plugin code to grab the contents of the file.
The Unsupported Appstore checks for available updates by referencing GitHub's RSS feed for each relevant repository. It would be possible to incorporate that code into your plugin but IMO it seems like more trouble than it's worth. If you're thinking of making things simpler for yourself and your beta testers before eventually submitting to the official Channel Directory, then adding your channel to the Unsupported Appstore probably makes the most sense.
Thanks. That made perfect sense and I was able to get it to work.
Now, looking further at the code of the Unsupported Appstore , I need to look more into the Dict[] function and how it works. In the Appstore example you gave above at https://github.com/mikedm139/UnSupportedAppstore.bundle/blob/master/Contents/Code/__init__.py#L48, how is Dict['plugins'] passed on to the next function? Or does calling it that way make it global?
Which I do not understand the "sender" on his functions either.
Good to know that it is not worth the trouble to try to add update code. If I think it needs more testing or isn't suited for the official Channel Submission, I will consider submitting it to the Unsupported Appstore.
The channel code for the Unsupported Appstore is actually out of date (v2.0 rather than v2.1). Ignore the "sender" arguments, they are irrelevant relics of a bygone era. The Dict[] is a form of global persistent storage available to channels. It uses the form of a dictionary (json formatting). You can add things to it and reference it later from anywhere in your plugin code.
Thanks Mike, that could be quite useful when pulling from a JSON file. I will have to play around with that some more.
I want to add some error checking to a channel I am writing that verifies the the url is valid and that there is a Plex URL service for it. What would be the best way to do this?
I was thinking of maybe a try except where the try sends some type of simple request to the URL service for the given url and if it enters the except you know there is a problem. But I am not sure where it would fit into the code. Since by the time it is producing videos, if the url is incorrect it would produce an error and be too late. Could you set it up as a separate function that just returns a true/false value, Then set up your video producing function to call that function and if true produce videos?
Or is there some type of built in function for this and am I making this much more complicated than it needs to be?
Hello shopgirl284!
You could do the try/except trick and see if something comes back (inside try) and ignore or continue if something fails (with except). The biggest issue with this approach is that the URL Service will most likely do 1 or more HTTP requests. If you have a list with videos to check, this can take a long time before the list is processed.
A forum user found out that you can do this to find out if there's a URL Service for a URL:
if URLService.ServiceIdentifierForURL(url) is not None:
oc.add(...) # add the video to the ObjectContainer, or do something else
Source: http://forums.plexapp.com/index.php/topic/45322-check-for-existing-url-service/
Thanks. I needed to check the validity of urls one step before the function that produces videos, so I just used a try except for that part since the function I used it on did not go through that many loops.
But then I tried to add the URLService.ServiceIdentifierForURL(url) code around the function that does produce videos and had issues with it. It didn't work for me. It returned videos as not working with the Plex URL service, even though without the code they produced and returned video lists and the videos played without the code. But I will post the details of those problems in the forum post you gave a link to above, so all the questions about that code will be in one place.
What exactly are these commands below for? Sadly, I have them in the start section of my channel mainly because all channels seemed to include them, but I cannot say I understand exactly why or what they do.
Plugin.AddViewGroup("List", viewMode="List", mediaType="items")
HTTP.CacheTime = CACHE_1HOUR
HTTP.Headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/20100101 Firefox/18.0'
The last one definitely seems like more of a command that appears to be more specific to your particular setup and system and is not needed in the code.
The first command is a left-over from when plugins had more control over how the contents were displayed. ViewGroups were defined to tell the client how to display the contents of the directory. Now, most (if not all) clients have a fairly rigid model for what types of content get display in which way. Generally, I try to remove the ViewGroup code from plugins when I'm updating them since it gets ignored anyways. (That is when I remember to do so)
The second line is setting a global cache time for all HTTP requests made by the plugin. This over-rides the framework's default cache period which, I don't remember off the top of my head. It is entirely optional, but if you're going to use it, the idea is to pick a cache-time that is reasonable. Ie. store data for a long enough time that you can realistically reduce the load on external servers as well as speed up the load-time for HTTP-requests, but not so long that changes/additions are not caught in a reasonable time frame. IMO, unless you specifically want/need a specific cache-length, I would remove that line and allow the framework to manage the cache with its default settings.
The third line is assigning a specific User-Agent header for all HTTP requests made by the plugin. Generally speaking, each time a plugin is started, a user-agent is randomly selected from a list to be used for all HTTP requests. In some cases, a plugin will perform better using a specific user-agent instead of a randomly assigned one. For example, some websites return different data for Safari on an iPad, then what they return for Chrome or Firefox on a PC. Again, if you don't have a specific need to set a specific user-agent, I would remove that code from your channel.
Thank you so much that made perfect sense. I will make sure to go back and clean up my code
OK here is another general question on the subject of channel design. How much error checking do you add to your programming? Do you just do enough to address any of the minor exceptions you find when testing your channel? Or do you add in extra to try to prevent unforeseen errors or future problems that may arise from design changes from the website.
At first I was thinking I needed to add more error checking in my code, even though it works fine as is. I am having trouble thinking of examples right now other than verifying that the data that is returned is accurate like for example a test for urls. Or better processing of exceptions with more specific error codes (which probably wouldn't affect the speed of the code).
I guess I am just worried I am not being thorough enough in my coding.
But when it comes to channel programming, you want it to be as light and fast as possible. If you add too much unneeded code, it slows down the channel. So why add extra code for possible future problems, when it works fine for now without it and would only slow it down?
It's fairly common practice to include a check for empty directories and return a message rather than display an empty menu. You've probably seen code like this in some of the plug-ins you've looked at:
if len(oc) > 0:
return oc
else:
return ObjectContainer(header=NAME, message="There are no contents available")
Beyond catching empty directories, you're only really guessing as to what sorts of problems the content provider can/will cause you in the future. At best, you might be able to prevent a minor change from preventing the channel from loading any content. Realistically though, if you're too aggressive with your error catching, the automated tester won't notice anything wrong when website changes cause missing content and it will take longer for users to notice and report the issues if the channel still partially works.
I have seen the empty menu message. I will make sure to include those.
Here is a question that I know is beyond my newbie status, but can you add entries to a JSON data file from your channel programming or at least edit them?
It’s possible but beyond the realm of a “normal” channel. It’s also likely to be unnecessary. If your channel loads the values from the JSON file into the plugin Dict on first-run, then you only need to modify or add to the Dict rather than worry about handling file I/O yourself. Since the Dict is persistent storage, you only need to confirm that your data is there when the plugin first loads so you can skip re-loading it from the JSON file.