Archive:HOW-TO:Write plugins for XBMC

From Official Kodi Wiki
Jump to navigation Jump to search
Time.png THIS PAGE IS OUTDATED:

This page or section has not been updated in a long time, no longer applies, refers to features that have been replaced/removed, and/or may not be reliable.

This page is only kept for historical reasons, or in case someone wants to try updating it.

Emblem-important-yellow.png THIS PAGE IS DEPRECATED

This page may still contain useful information

XBMC includes support for writing Add-Ons written in Python.

Plugins, unlike scripts, do not generally provide new functionality to XBMC, instead they provide an easy way to present content listings in XBMC through the native GUI interface. Content is usually online audio and video streams like YouTube, Vimeo or podcasts, or pictures from websites such as Flickr or Picasa.

Please feel free to add samples of simple plugin functions. Add anything at all no matter how basic, if it is not already here add it! Someone will more than likely benefit from it. Don't be stingy on the comments you can never have too much information, what's simple to you may make no sense at all to someone else. Any relevant URLs that were helpful to you Would be helpful as comments as well.

For end-user instruction on how to install XBMC plugins please see Add-on manager.

Note! As most plugins work by scraping a website they often stop working (partially or completely) when the source website changes (redesign). If a third-party plugin doesn't work it is not usually an XBMC problem.

Introduction/Prerequisites

Helpful tools:

There's also lots of streaming sources available for building plugins:

Before you begin, search the XBMC forum for the name of the plugin you are planning on creating. It may already exist. Install Python and find where you put the source code.

Right click on the file 'Default.py' and select 'Edit with IDLE'.

Plugin Template : Breakdown.

This is just to familiarise yourself with the layout of the plugin template. It's not in depth – we will delve deeper later.

Remember – it's all about the Tabs.

Python is just like you and I, it has the ability to use information from other sources. If you don't know anything about Python – you can read a book from a library and gain the knowledge. Therefore it's the same with a Python & its libraries. A Python Library is a collection of useful functions that the main program can call upon and read then use the new knowledge in the main program.

To use them we need to import them, you will only use 5 at maximum for basic plugin creation.

import urllib,urllib2,re,xbmcplugin,xbmcgui

  • urllib – a collection of http routines.
  • urllib2 – a more advanced collection of http routines.
  • re – a collection of string manipulation routines.
  • xbmcplugin – specific Xbmc routines.
  • xbmcgui – specific Xbmc routines.

Without the above imports, python has no reference and the plugin will error and fail.

The next thing you will see is the (CATEGORIES () : ) function. This handy little function takes the stress out of XBMC Directory listing. It's really the addDir() that lists & adds - but we are not in depth - YET.

def CATEGORIES():
      addDir("","",1,"")
      addDir( "","",1,"")
      addDir( "","",1,"")
      addDir("","",1,"")

You define a function in python with the def command. This function adds the first Directories that you see when you start the plugin. Let's break it down. Scan down the Plugin template.

def addDir(name,url,mode,iconimage):
    u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"name="+urllib.quote_plus(name)
    liz=xbmcgui.ListItem(unicode(name), iconImage="DefaultFolder.png",thumbnailImage=iconimage)
    liz.setInfo( type="Video", infoLabels={ "Title": name })
    ok=xbmcplugin.addDirectory(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
    return ok


I'm not going to go into too much detail here, when you call the addDir()command you are calling the above function. All that is happening is a name, url, and image are being passed to XBMC in a format it likes and it's being told to display it.

name = The name of the Directory, either a string or the product of a scrape.

Python likes strings or stored strings.

To make a string, give it a name then type your string in quotes.

a= 'this is a string' , notice how it turns green.

For the name that addDir needs you can either pass it a string.

addDir('string', , 1 , ) or a stored string addDir(name, , 1 , )

We will examine stored strings later.

url = The web address, either a string or the product of a scrape.

As above pass either a string ' hxxp://www.testing.com' or a stored url string – url.

Next on the list is:

mode = Where in the program to jump to .

Look at the bottom of the Template.

if mode==None or url==None or len(url)<1:
        print ""
        CATEGORIES()
     
elif mode==1:
        print ""+url
        INDEX(url)
        
elif mode==2:
        print ""+url
        VIDEOLINKS(url,name)

We have 3 modes here, but, you can have as many as you need.

  • mode0 = CATEGORIES()
  • mode1= INDEX(url,name)
  • mode2=VIDEOLINKS(url,name)

So in the CATEGORIES () : function, we call addDir(,,1,) which tells the plugin to move on to mode 1 = INDEX(url).

Tell Xbmc to add the first Directories then move on to INDEX function.

See it's not awful.

The last term here is :

Iconimage = An image for display with the Directory or link, either string or stored string. Basically a thumbnail.

addDir (name, url , 1 , 'http://testing.com/image.gif') or a stored string addDir(name, url , 1 ,thumb )

Xbmc can handle pretty much all image formats : jpg ,gif, png etc

The addLink(name,url,iconimage) is exactly the same except the isfolder= option is set to false to tell Xbmc that this is a video link and not a folder.

The next Function is the INDEX (url) : this opens the webpage of your chosen website, pretends to be a browser, reads it, stores the page and then scans the page for links to the sacred video files.

def INDEX(url):
        req = urllib2.Request(url)
        req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3')
        response = urllib2.urlopen(req)
        link=response.read()
        response.close()
        match=re.compile('').findall(link)
        for thumbnail,url,name in match:
                addDir(name,url,2,'')

We are going to call on the urllib2 library not the urllib library to connect to the web page because we can spoof the website into believing that the plugin is a real person using a browser.

req = urllib2.Request(url)
req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3')

url - is the web address that we passed during the previous CATEGORIES () - addDir(name, url , 1 ,thumb )

We have added a header, User-agent. This allows Python to pretend to be anything else, Firefox, Internet Explorer,Ipod,Phone,Veoh.

We can send any headers here using the same format. Just copy the req.add_header and put it under the other one.

Some sites need specific headers to access their information. This pretends to be the latest Firefox.

req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3')
req.add_header('Content-type', 'octet-stream/flv')

response – adds the req calls and causes connection with the webpage.

response = urllib2.urlopen(req)
link=response.read()			- Holds the webpage that was read via the response.read() command. 
response.close()				- Closes the connection after we have read the webpage.
match=re.compile('').findall(link)
for thumbnail,url,name in match:

link - is the holder for the page url from CATEGORIES that was read. We close the open connection as we have the page and want to save memory.

Now we scrape the screen for the relevant information. We are using the re library here:

match=re.compile("").findall(link)

match- is the holder for the compiled bits of information we have scraped. We will explore this in depth in the next part of the tutorial.

Just familiarise yourself for now.

Open hxxp:/xbmc.org/forum/register.php in your browser ( I use firefox ).

Right click and select View page source. Scroll right down to the bottom of the page do you see : -

<div class="smallfont" align="center">

To scrape the words smallfont and center we would use –

match=re.compile('<div class="(.+?)" align="(.+?)">').findall(link)

so match now holds – smallfont and center. The order matters so remember smallfont is first, center is second. Imagine that this was the url and name of a video.

  • match[0] = smallfont
  • match[1] = center

You can experiment with regular expressions like those using a free online tool like RegExr.

Lets move on.

for ? in match:- Gets all the information stored in match and creates multiple links or directories on your screen.

for url,name in match:
	addDir(name,url,1,'')

url = The first thing held in match name = The second

You can call them whatever you wish.

So a directory will be created named center with the url smallfont As you can see the VIDEOLINK() function is just the same really, except for addLink instead of addDir.

Minimize the template, open your browser, right click -->edit with idle - on test.py and lets really do something.

If you are still unsure about what you have read, re–read.