Not sure what's wrong with my code.

so I’m writing a sportsdevil plugin. Right now I’m having problems populating the list of sports to be able to choose from. If i write it out as:

def MainMenu():
oc.add(DirectoryObject(key=Callback(SubList, title=’/Football’, url=‘http://thefeed2all.eu/type/american-football.html’), title=‘Football’))
return oc

It shows up just fine, but i don’t want to write it out for every sport. If i write it as:

def MainMenu():

url='http://www.thefeed2all.eu/type/football.html'
html = HTML.ElementFromURL(url)
oc = ObjectContainer(title2=TITLE)
for node in html.xpath('//tbody/tr/td'):
    title = node.xpath('/a/font/text()')[0].strip()
    url_sport_page = node.xpath('/a')[0].get('href')
    oc.add(
    DirectoryObject(
    key=Callback(
    SubList, title = title,
    url = url_sport_page,
    title = title)))
return oc

It doesn’t show any object to select. Any ideas?

That is because your for loop is empty. When you do an xpath pull without a [0] on the end, it returns a list. And since a list can be empty, you will not get an error for an xpath pull of a list, it will just return an empty list ([]). So in the example you gave above, since there are no “node” values in the list of your for loop, it just skips that for loop.

When I have problems with my xpath lists, I usually separate the list pull and add some log messages to see what it is pulling. And “View Xpath” option in Firefox is great to see what actually being pulled.
node_list = html.xpath('//tbody/tr/td') Log('the value of node_list is %s' %node_list) For node in node_list:

Also realize that when you use xpath to pull a list and then pull specific items in that list with additional xpath, you need to put a dot in the xpath for the specific pull, other wise it is not even using the xpath in your for loop.

This code pulls the title variable using “html.xpath(’/a/font/text()’)[0]”:
for node in html.xpath('//tbody/tr/td'): title = node.xpath('/a/font/text()')[0].strip()
This code pulls the title variable using “html.xpath(’//tbody/tr/td/a/font/text()’)[0]”:
for node in html.xpath('//tbody/tr/td'): title = node.xpath('./a/font/text()')[0].strip()
Also, it is just good practice to add this code to the bottom of any function you have that does not have hardcoded items in it (hardcoded meaning like your first example where you wrote it out):
if len(oc) < 1: return ObjectContainer(header=L('Empty'), message=L('There are items to display')) else: return oc

you’re the best shopgirl284,

I rewrote the code as:
def MainMenu():

url='http://www.thefeed2all.eu/type/football.html'
html = HTML.ElementFromURL(url)
node_list = html.xpath('//body/table/tbody/tr/td/table/tbody/tr/td')
Log('the value of node_list is %s' %node_list)
oc = ObjectContainer(title2=TITLE)
for node in node_list:
    title = node.xpath('./a/font/text()')[0].strip()
    url_sport_page = node.xpath('./a')[0].get('href')
    oc.add(
    DirectoryObject(
    key=Callback(
    SubList, title = title,
    url = url_sport_page,
    title = title)
    )
)
if len(oc) < 1:
    return ObjectContainer(header=L('Empty'), message=L('There are items to display'))
else:
    return oc

And you’re right. The log shows node_list being returned as empty. When i look at firefox’s ‘view xpath’ at the list of nodes for the different sports it shows:

/x:html/x:body/x:table/x:tbody/x:tr/x:td/x:table[2]/x:tbody/x:tr/x:td[1] with a namespace: x

Is this the reason node_list is being returned as empty? or should what i have work?

Glad it helped.

But one note, I use Firefox “View Xpath” just to test my xpath that I want to use(meaning xpath I have chosen from looking at the source of the website), not to find what xpath Firefox would use.

You want to find the simplest, shortest xpath that only pulls the section you want when you pull data. Otherwise, adding all that junk to the beginning of your xpath, means that even a simple change to their website will break your channel.

The “Tips for using Xpath” section of this support document, support.plex.tv/hc/en-us/articles/201169597-Using-Chrome-s-Built-In-Debugger-for-Channel-Development, explains this concept well.

Well just for kicks i decided to rewrite the code to point to http://ifirstrowus.eu/ instead of http://thefeed2all and the damn thing came to life after playing with the nodes. So the main menu is being populated and the values are being carried through to SubList(). I’m really really curious to know why it wouldn’t work for the first site, but is working for this new one.

Anyways the new error I’m getting is:
AttributeError: ‘NoneType’ object has no attribute ‘sandbox’
Which from what i can gather has to do with the ServiceCode.pys
I can’t find anything on the stream that is coming in and i don’t know what the container or codecs are. Is this still required? The different plugins that I’ve looked at seem to handle this differently, but there doesn’t seem to be much guidance out there on the subject.

That website is providing streams from all over the place, so you’ll have to write URL Services for each and every streaming source site that’s being used on the site…

As I told you in this post forums.plex.tv/discussion/comment/1122448/#Comment_1122448, the URL service is the hardest part of writing a channel and it just takes a lot of work to find the real sources of the media streams.

When I start a new channel project, if there is not already a URL service for that website in the Services bundle, before I even write the first line of code for my channel bundle (the init.py file), my first step is to figure out how and if I even can find and pull the media streams and their info for that website.

I have often looked at a website and considered making a channel for it. But because I could not figure out how to successfully write the code to pull the media streams and info, I knew I could not create the necessary URL service to make the videos actually play. So I dropped the idea for that channel and just moved on.

These templates can give you a basic idea about the parts of and functions within a URL service - support.plex.tv/hc/en-us/articles/201199076-Development-template. But since each website will be different, no one can really create a step-by-step how-to guide for locating and pulling the media streams and info from a website.

Ok so now I’ve hit another roadblock. I’m trying to populate the menu with the match times and I’ve spent a good 5 hours trying to figure this thing out. Maybe I’m not wording my question right on google. It’s not super important, but i don’t like putting this much time into something without completing it fully.

page:
" < span >< span class=“matchtime” >16:01< /span > "

when i try to pull the time using:
time = node.xpath(’./a/span/span/text()’)[0].strip()

and it returns an error of:
IndexError: list index out of range

I’ve tried a BUNCH of stuff on it thinking that the colon was causing the issue as all my other identical pulls were successful, but the pull without the ‘[0]’ returns an empty list in the log. I want to pull it as a string so i can display it before the match_name. I guess the colon isn’t that important either :confused:

And i know i’m probably being an idiot about this, but I’m really drawing a blank on the whole URL service thing. I used firebug and found that the source should be:

< embed width=“100%” height=“100%” type=“application/x-shockwave-flash” flashvars=“controlbar=over&skin=http://thecdn.04stream.com/p/skin.swf&logo=http://thecdn.04stream.com/p/slogo.png&link=http://castlive.tv&bufferlength=1&autostart=true&fullscreen=true&displayclick=link&file=rtmp://46.28.49.36:1935/stream/1KqBo2018y0yBo68GX6Kc.stream?q6167e886od1682o472sp6972b1682on556w6972id1682o472sn556w6972im88u472yb6972n263pq886t6167uq88x3929i&height=440&width=600” src=“http://thecdn.04stream.com/p/ooolo1.swf” allowscriptaccess=“always” wmode=“transparent” allowfullscreen=“true” >

I’ve looked at other plugins and understand how they call videos, but those (for the most part) point to a direct stream link that I’ve been able to plug into vlc without a problem. I’ve looked through the original SportsDevil plugin for Kodi and it looks like it uses the src=“http://thecdn.04stream.com/p/ooolo1.swf” to pull the video. Once i understand how to do it I’m sure i won’t have a problem with adding in more URL Services for the different streams (fingers crossed).

I’m fairly sure that once i get those 2 things down it’ll be ready and I’ll throw it up on github :slight_smile:
All the menus, aside from the times, are set up correctly and everything is being pulled in without a hitch.
Honestly though shopgirl284 you have pretty much been a godsend with this :slight_smile: It would’ve taken way longer without you popping in to help out.

Span codes can be tricky with xpath, though the one you mentioned is easy if you just add the class distinction like mydata.xpath(’//span[@class=“matchtime”] ').

But often they will put spans inside of spans in a way that you have to either pull the whole list or add a number to your pull to specify which span you want. If you play with the Firefox xpath view and try things like //span/text(), //span//text(), and //span[1]/text() you will see how it will give you different results including some multiples for each list xpath from your for loop. And remember since these xpath pulls are pulling from an xpath list in your for loop, their may be multiple results linked to each for loop xpath, but since you added that [0] to the end, it will only return the first one it finds.

As for the URL service stuff, Plex does not work with Webkit. You have to find the media streams like other URL services (that is why they work).

Writing a channel bundle is the easy part. Whether you separate it into a URL service or just build the media objects in your channel, writing the code to build those media objects so the videos will play is very difficult. Anyone who tells you differently has probably been doing this or similar things for too long to remember when it was hard (its like someone who knows differential equations telling someone with only basic math skills that algebra is easy). As I said above, I have had to just abandon projects, because I could not figure out how to access the stream URLs or access them the way I needed to build the media objects.

The reasons any of us use Plex and Plex channels over other media products, is because they are better. Plex channels provide a better interface (look prettier), work on multiple players/client, provide easier navigation and more options and do not require nearly the CPU power of other programs. But those things that make Plex channels better also make their development more difficult.

I am including a link to a support document I have been working on called URL services for Dummies, docs.google.com/document/d/1ePST3Dk0KywSmmDu3OPqpiNilpVgZDSzPgB0ns1yiFU. It is still a rough draft, so there may be errors, but it may help you figure out your URL service issue or at least whether the project is worth it, especially the section at the end “How do I write the PlayVideo() function and/or find the media streams needed to build the media objects?”

@shopgirl284 said:
Span codes can be tricky with xpath, though the one you mentioned is easy if you just add the class distinction like mydata.xpath('//span[@class=“matchtime”] ').

But often they will put spans inside of spans in a way that you have to either pull the whole list or add a number to your pull to specify which span you want. If you play with the Firefox xpath view and try things like //span/text(), //span//text(), and //span[1]/text() you will see how it will give you different results including some multiples for each list xpath from your for loop. And remember since these xpath pulls are pulling from an xpath list in your for loop, their may be multiple results linked to each for loop xpath, but since you added that [0] to the end, it will only return the first one it finds.

I’m at a loss for words words. I swore i tried that. I guess that’s what happens when you try to code and don’t sleep =S Well it works perfectly now thanks :slight_smile: I’ll check out your support document.

I have done that before, usually because I missed a quotes or closing bracket, parenthesis, etc.

That points out another advantage to running your xpath code through that xpath view in Firefox. It will tell you if your xpath is a syntax error vs no matches as well.

Ran into the same issue again, but only for certain sport pages. Turns out that the issue was when constant streams (that have a time of ‘00:00’) had the value located in h3/a/span/text() and had some weird namespace, and the others that had a normal time (ex: ‘04:00’) had it located in h3/a/span/span/text(). I ended up getting around it with:

for node in match_times:
rough_time = node.xpath(’.//span[@class=“matchtime”]/text()’)
if len(rough_time) > 0:
match_time = node.xpath(’.//span[@class=“matchtime”]/text()’)[0].strip()
else:
match_time = ‘00:00’

xpath has been pretty awesome though. It was my bad. I should have looked at every entry path for all the pages. Lesson learned :slight_smile:

You will have some where it is best to pull the list of xpath and then look for the one you want, but sometimes, if the xpath code is not there and it will cause an error, it is better to just use a try/except to skip the xpath exceptions.

try: match_time = node.xpath('.//span[@class="matchtime"]/text()')[0].strip() except: match_time = '00:00'
Another thing I do a lot is if I have the issue, I will break up the steps of the code and use Log messages to see what is really going on along the way.

match_time_list = node.xpath('.//span[@class="matchtime"]/text()') Log('the value of match_time_list is %s' %match_time_list) match_time = match_time[0] Log('the value of match_time is %s' %match_time) match_time =match_time.strip() Log('the value of match_time is %s' %match_time)

Then once you see what you have and are pulling all the things you want, you can combine the steps more like I did in the first example. And you will never find all the issues until you just try to open all the directories and test it in a Plex player app.