Archive:HOW-TO:Write plugins for XBMC: Difference between revisions

From Official Kodi Wiki
Jump to navigation Jump to search
>Voinage
No edit summary
No edit summary
 
(47 intermediate revisions by 18 users not shown)
Line 1: Line 1:
XBMC features a [http://en.wikipedia.org/wiki/Python_%28programming_language%29 Python Engine] and XBMC GUI interface have built-in 'Add-on' support for displaying content listings that present to that GUI interface.
{{outdated}}
{{Notice|raw='''<big>THIS PAGE IS DEPRECATED</big>'''<br />
This page may still contain useful information}}


Plugins, unlike [[HOW-TO write Python Scripts|scripts]], do not really provide new functionality to XBMC, instead what they do do is provide an easy way to present content listings in XBMC through the native GUI interface.
XBMC includes support for writing Add-Ons written in [http://en.wikipedia.org/wiki/Python_%28programming_language%29 Python].
Content is usually online sources like Internet audio and video streams, (like Internet TV-channels, and radio-station, or Podcasts), or pictures from websites which as Flickr and Picasa Web.


Please feel free to add more samples of simple plugin functions with comments that you know or figure out while you are learning to write or edit plugins for XBMC. Adding anything at all no matter how basic, if its not already here add it! someone will more then likely benefit from it. The more difficult your snippet please heavily comment it with "#" 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, also URLs that were helpful to what you were doing would be great to add to your snippet or to the bookmark section (python sites, chat rooms, etc).
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.


This a placeholder that so far is just a copy of the beginning of [[HOW-TO write Python Scripts]].
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 intruction on how to install plugins for XBMC please see [[HOW-TO install and use plugins in XBMC]].
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 changes (redesign) are made to the website by the website owner. So if a third-party plugin do not work know that it is not usually do to a problem with XBMC but rather the website it scrapes have had changes done to it, meaning someone will have to manually edit the plugin code to account for the new changes, then you will have to get that updated version of the plugin.
'''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.


=Writing plugins in python for XBMC=  
= Introduction/Prerequisites =
     
'''Introduction.'''


Hello, I`m Voinage - '''Team XBMC Python Coder & Plugin Nutcase.'''
Helpful tools:


This tutorial has been tested over '''2000''' times at the point of writing and
* Wireshark - http://prdownloads.sourceforge.net/wireshark/
i know that i can help you write a plugin by the end of this read through..
* Python - http://www.python.org/download/
* Tutorial source code – http://voinage-xbmc-plugins.googlecode.com/files/Plugin-tutorial.rar


I`m here to help you light that fire under the crucible of coding, the coddle-pot of collective communal creation:
There's also lots of streaming sources available for building plugins:


'''In other words XBMC plugin coding.'''
* The [http://www.ovguide.com/ OVGuide].
* You can also check the [http://forum.xbmc.org/forumdisplay.php?fid=27 Add-ons Help and Support] here.  


'''Onwards, the riot has begun ! I demand it people, It`s alive !'''
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.


Python Plugin coding can be frustrating, but VERY rewarding.
Right click on the file 'Default.py' and select 'Edit with IDLE'.
Imagine watching that episode of your favourite Tv show on your Tv, instead of on your laptop lcd or monitor - thinking about it ?


Good, let`s get started.
= Plugin Template : Breakdown. =
 
'''You will need :-'''
 
''Yourself , Concentration , Determination.''
 
*Wireshark - http://prdownloads.sourceforge.net/wireshark/wireshark-setup-1.0.4.exe
 
*Python - http://www.python.org/download/
 
*Tutorial source code – http://voinage-xbmc-plugins.googlecode.com/files/Plugin-tutorial.rar
 
 
Selecting a target, sounds easy.
 
I`ll just pick what I like, great.
 
Don`t release it, enjoy it yourself.
 
Just because you like Tropical fish videos doesn`t mean the Community will.
 
*Try here : http://www.ovguide.com/  - plenty of streaming targets , eh ?
*Now, check my requests thread here - http://forum.xbmc.org/showthread.php?t=33668
 
 
Also, search the XBMC forum for the name of the Plugin you are planning on creating. It may already exist.
Don`t duplicate, what`s the point. You spend hours on a plugin only to find that one already exists and just needs fixing. 
 
''Have you checked the Threads & searched the Forum ?''
 
'''Remember the 3 C`s :-  Consider, Community, Content.'''
 
Install Python and find where you put the source code that came with this tutorial.
 
Right click on : - Default.py  and select --> Edit with Idle.
 
Don`t be afraid, this is the fun part.
Honestly, it is.
 
=Plugin template : Breakdown.=


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


''Remember – it`s all about the Tabs.''
''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.  
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 & it`s libraries.
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.
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.


Line 85: Line 45:
'''import urllib,urllib2,re,xbmcplugin,xbmcgui'''
'''import urllib,urllib2,re,xbmcplugin,xbmcgui'''


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


Without the above imports, python has no reference and the plugin will error and fail.
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.
The next thing you will see is the ('''CATEGORIES () : ''') function.
This handy little function takes the stress out of XBMC Directory listing.
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''.
It's really the '''addDir()''' that lists & adds - but we are not in depth - ''YET''.
<python>
<source lang="python">
def CATEGORIES():
def CATEGORIES():
       addDir("","",1,"")
       addDir("","",1,"")
Line 102: Line 62:
       addDir( "","",1,"")
       addDir( "","",1,"")
       addDir("","",1,"")
       addDir("","",1,"")
</python>
</source>


You define a function in python with the '''def''' command.
You define a function in python with the '''def''' command.
This function adds the first Directories that you see when you start the plugin.
This function adds the first Directories that you see when you start the plugin.  
Let`s break it down. Scan down the Plugin template.
Let's break it down. Scan down the Plugin template.
<python>
<source lang="python">
def addDir(name,url,mode,iconimage):
def addDir(name,url,mode,iconimage):
     u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"name="+urllib.quote_plus(name)
     u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"name="+urllib.quote_plus(name)
    ok=True
     liz=xbmcgui.ListItem(unicode(name), iconImage="DefaultFolder.png",thumbnailImage=iconimage)
     liz=xbmcgui.ListItem(name, iconImage="DefaultFolder.png",thumbnailImage=iconimage)
     liz.setInfo( type="Video", infoLabels={ "Title": name })
     liz.setInfo( type="Video", infoLabels={ "Title": name })
     ok=xbmcplugin.addDirectory(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
     ok=xbmcplugin.addDirectory(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
     return ok
     return ok
</python>
</source>






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.
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.
'''name''' = The name of the Directory, either a string or the product of a scrape.
Line 126: Line 85:
  To make a string, give it a name then type your string in quotes.
  To make a string, give it a name then type your string in quotes.


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


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


'''addDir(`string’, ’’ , 1 , ’’)''' or a stored string '''addDir(name, ‘’ , 1 , ’’ )'''
'''addDir('string', '' , 1 , '')''' or a stored string '''addDir(name, '' , 1 , '' )'''


We will examine stored strings later.
We will examine stored strings later.
Line 136: Line 95:
'''url''' = The web address, either a string or the product of a scrape.
'''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.
As above pass either a string ' hxxp://www.testing.com' or a stored url string – url.


Next on the list is:
Next on the list is:
Line 144: Line 103:
Look at the bottom of the Template.
Look at the bottom of the Template.


<python>
<source lang="python">
if mode==None or url==None or len(url)<1:
if mode==None or url==None or len(url)<1:
         print ""
         print ""
Line 156: Line 115:
         print ""+url
         print ""+url
         VIDEOLINKS(url,name)
         VIDEOLINKS(url,name)
</python>
</source>


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


*'''mode0''' = CATEGORIES()
* '''mode0''' = CATEGORIES()


*'''mode1'''= INDEX(url,name)
* '''mode1'''= INDEX(url,name)
*'''mode2'''=VIDEOLINKS(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)'''.  
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.
Tell '''Xbmc''' to add the first Directories then move on to '''INDEX''' function.


See it`s not awful.
See it's not awful.


The last term here is :
The last term here is :
Line 177: Line 136:
Basically a thumbnail.
Basically a thumbnail.


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


'''Xbmc''' can handle pretty much ''all image formats : jpg ,gif, png etc''
'''Xbmc''' can handle pretty much ''all image formats : jpg ,gif, png etc''
Line 184: Line 143:
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 '''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.
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.


<python>
<source lang="python">
def INDEX(url):
def INDEX(url):
         req = urllib2.Request(url)
         req = urllib2.Request(url)
Line 197: Line 156:
                 addDir(name,url,2,'')
                 addDir(name,url,2,'')


</python>
</source>


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.
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.


<python>
<source lang="python">
req = urllib2.Request(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')
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')
</python>
</source>


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


We have added a header, User-agent.  
We have added a header, User-agent.  
Line 218: Line 177:
This pretends to be the latest Firefox.
This pretends to be the latest Firefox.


<python>
<source lang="python">
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('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')
req.add_header('Content-type', 'octet-stream/flv')
</python>
</source>


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


<python>
<source lang="python">
response = urllib2.urlopen(req)
response = urllib2.urlopen(req)
link=response.read() - Holds the webpage that was read via the response.read() command.
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.
response.close() - Closes the connection after we have read the webpage.
match=re.compile('').findall(link)
match=re.compile('').findall(link)
for thumbnail,url,name in match:
for thumbnail,url,name in match:
</python>
</source>


'''link''' - is the holder for the page url from '''CATEGORIES''' that was read.
'''link''' - is the holder for the page url from '''CATEGORIES''' that was read.
Line 246: Line 205:
Just familiarise yourself for now.
Just familiarise yourself for now.


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


Right click and select '''View page source.'''
Right click and select '''View page source.'''  
Scroll right down to the bottom of the page do you see : -  
Scroll right down to the bottom of the page do you see : -  
   
   
Line 257: Line 216:
To scrape the words '''smallfont''' and '''center''' we would use –  
To scrape the words '''smallfont''' and '''center''' we would use –  


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


so '''match''' now holds – '''smallfont and center.'''
so '''match''' now holds – '''smallfont and center.'''
Line 265: Line 224:
Imagine that this was the url and name of a video.
Imagine that this was the url and name of a video.


*'''match[0] = smallfont'''
* '''match[0] = smallfont'''
*'''match[1] = center'''
* '''match[1] = center'''
 
You can experiment with regular expressions like those using a free online tool like [http://gskinner.com/RegExr/ RegExr].


''Lets move on.''
''Lets move on.''
Line 272: Line 233:
'''for ? in match:'''- Gets all the information stored in match and creates multiple links or directories on your screen.
'''for ? in match:'''- Gets all the information stored in match and creates multiple links or directories on your screen.


<python>
<source lang="python">
for url,name in match:
for url,name in match:
addDir(name,url,1,’’)
addDir(name,url,1,'')
</python>
</source>


'''url''' = The first thing held in match
'''url''' = The first thing held in match
Line 285: Line 246:
As you can see the '''VIDEOLINK()''' function is just the same really, except for '''addLink instead of addDir.'''
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.
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.'''
'''If you are still unsure about what you have read, re–read.'''
==Test, test, test again.==
Right,  let`s have some fun.
Open your Browser ( I use Firefox for the tutorial)
'''Ctrl & click the link :''' -  http://www.ovguide.com/
Scroll down – see TV DASH,  that`s the fellow for this tutorial.
'''Click it or Ctrl & click the link :''' - http://www.tvdash.com/
Once it`s open – Bookmark it.
[[Image:image1.jpg]]
Excellent Choice, at first glance we have thumbnails for the movies & tv – great for Xbmc.
The site looks clean and tidy – great for grabbing urls, without headaches.
Look at the '''top center of of the screen, Home, movies, tvshows,games.'''
They will become our main directories and as there are only two that we need, we will add them manually. 
Before we do that lets get the scraping and testing done.
'''Click on the  ‘ MOVIES ‘  link.'''
[[Image:image2.jpg]]
A lovely list of movies, ha, nothing makes me feel more like a Pirate than this – Aaargh Jim`lad.
'''Hoist the test.py'''
'''Remember the name of the first movie listed here''', we will need it later.
First copy the url from the address bar of your browser.
Right click and copy.
Click to restore the '''test.py''' window you will see this or something like it.
<python>
import urllib2,urllib,re
url=' Delete me'
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=lemon.read()
response.close()
match=re.compile('Delete me 2').findall(link)
print match
</python>
Click and delete the text '''url="Delete me" ---> url=" "'''
   
Replace it with the url you have stored.''' Ctrl & V. '''
'''url="hxxp://www.tvdash.com/movies.html"'''
'''Press  '''‘ F5 ’''' – which is really run module in Python terms.
[[image:image3.jpg]]
The parentheses are the graphical representation of what`s stored in match.
'''In this case, nothing,  yet.'''
The  ‘''' Print  match''' ‘  command causes the display, you can print any variable or string.
Remove it by putting # in front of it  #print match see how it turns red.
Any text you put after a # character becomes a non-useable
'''note !''' -  Great for adding your plugin title.
The reason for the empty '''match''' variable is that we haven`t provided any regular expression to scrape the data, we will soon.
But for now, we have a nice Python shell open.
All commands are case sensitive so type exactly what you have in '''test.py''' only.
Type ‘'''print response.info()'''‘  -->ENTER    this will bring up the server response from the website.
[[image:image4.jpg]]
See how powerful Python is ?
This command is really useful, but not to be used just yet.
Sometimes Cookies that are required to access sites reside here and can be accessed and manipulated to your benefit.
Commands and tabulation is what Python is all about.
'''Back Sir/Madam, back I say, to your browser and let`s look at the source of the page.'''
'''Press Ctrl & U to view the page source.'''
At this point it is '''very easy''' to be put off, don`t be, once your eye is in – it becomes second nature.  Honest.
[[image:image5.jpg]]
Hmmm ....... Press '''Ctrl & f''' to bring up the search and enter the name of the first movie.
'''10 things i hate about you''' , Now this is more like it.
[[image:image6.jpg]]
The '''name, iconimage (Thumbnail), url are all here.'''
Great.
First, '''maximize your Python shell.'''
In your Python shell type : - '''link''' --->ENTER
Once it has completed, you will have a display of the webpage ready for scraping.
[[image:image7.jpg]]
Press '''Ctrl & f''' to bring up the search and enter '''10 things I hate about you''' --->ENTER
You will see the above section.
The highlighted area is exactly what we need, it has the '''thumbnail,name and url.'''
<nowiki>
src="http://farm4.static.flickr.com/3190/2881209823_799288181c_m.jpg" border="0" /></td>\n      <td class="namewidth"><a title="Watch 10 Things I Hate About You (1999) (Requested) Online" href="http://www.tvdash.com/movies/10_Things_I_Hate_About_You_(1999)_(Requested).html">10 Things I Hate About You (1999) (Requested)</a>
</nowiki>
The following bits are what we need for the tutorial.
*'''http://farm4.static.flickr.com/3190/2881209823_799288181c_m.jpg = Thumbnail'''
*'''http://www.tvdash.com/movies 10_Things_I_Hate_About_You_(1999)_(Requested).html = Url'''
*'''10 Things I Hate About You (1999) (Requested)</a> = name'''
To scrape the text we need to show Python what to take and where it is.
Have a go at highlighting that whole section, hold your left mouse button and drag it across the section.
Then press '''Ctrl & c to copy to clipboard.'''
Close your Python shell and restore your '''test.py'''
Place your cursor in between the ‘ ‘  of the '''match=re.compile ( ‘  ‘ ).findall(link)'''
Press''' Ctrl & V.''' You should see this.
<python>
match=re.compile(‘src="http://farm4.static.flickr.com/3190/2881209823_799288181c_m.jpg" border="0" /></td>\n      <td class="namewidth"><a title="Watch 10 Things I Hate About You (1999) (Requested) Online" href="http://www.tvdash.com/movies/10_Things_I_Hate_About_You_(1999)_(Requested).html">10 Things I Hate About You (1999) (Requested)</a>').findall(link)
</python>
The text between the single quotes is green because Python recognizes a string and highlights it.
*'''Green = good'''
*'''Red = bad''' , providing the code was not after the # character.
Python uses this to mark notes.
Future reference.
If the scrape has single quotes in it -  '''src= ‘ http://tester.html ‘'''
you will need to change the wrapping quotes – '''match=re.compile( ‘src= ‘ http://tester.html ‘  ‘ )'''
to ''' match=re.compile( “src= ‘ http://tester.html ‘  “ )'''  to not confuse Python.
Okay, let`s scrape that site.
There are many useful regular expressions that Python understands but generally for basic site scraping you only need  -  brackets around what you want to capture then delete the text and replace with: 
(.+?)  –  Yep, it really can be that simple – sometimes.
Let`s just say it means take everything inside the brackets – it is a basic tutorial. He,he.
When trouble brews and trust me , it will.
'''Try here for really in depth help – I did.'''
*http://www.amk.ca/python/howto/regex/
*http://www.python.org/doc/2.5.2/lib/re-syntax.html This will explain the true meaning.
*http://www.python.org/doc/2.5.2/lib/module-re.html
*http://www.regular-expressions.info/python.html
Shall we scrape ?
Following the tutorial - put brackets around what you want to capture then delete the text and replace with '''(.+?)''' we get :
<python>
match=re.compile('src="(.+?)" border="0" /></td>\n      <td class="namewidth"><a title="  .+?  " href="(.+?)">(.+?)</a>').findall(link)
</python>
So here we have scraped the image,url and name.
You noticed didn`t you.
One section has been replaced with '''.+?''' that is because that text will not be the same for every movie on the page.
If the movie is ‘''' Friday 13th''' ‘ it would say ‘'''Watch Friday 13th'''’
not ‘'''Watch 10 things I hate about you'''’ 
so we tell python to skip it with '''.+?'''
'''– No brackets, no scrape.'''
Let`s move on . .you should end up with thi . . .
What do you mean you`re not ready.
Okay go back and re-read the last section.
Honestly people today, wouldn`t have happened in my day  . .
Ready now ?
[[image:image8.jpg]]
Maximize your Python shell and type  '''>>>Match'''    --->ENTER
[[image:image9.jpg]]
Houston, we have an RE match.
The variable match now holds the information we wanted in the form of a '''Tuple.'''
[[image:tribble.gif]] No not a Tribble – bad Trekkie.
'''For information on tuples try here :'''
'''http://en.wikibooks.org/wiki/Python_Programming/Tuples'''
How many matches did we get ?
Let`s use the '''len()''' command – length of variable.
Type  '''>>>  len(match)''' -->ENTER
We get '''>>>251'''
so our RE pattern matched 251 times.
That`s 251 movies.
'''Python always starts indexing(counting) from zero.'''
So the first match is '''match[0] not match[1]'''
That means that the length really is '''250'''
so the to address the last item it is '''match[250] or match[-1]'''
'''A negative index number goes backwards''', handy eh.
Have a go, try a few things
'''>>>match[10] or match[-10] etc'''
We have 3 things stored in match try : '''match[0][0]        hmmmm'''
===Putting it together.===
Well where does that leave us ?
So far we have scraped some information and stored it in the variable match.
We have established that information stored in python variables can be accessed individually.
We have established how to read a webpage contents then store and display them in python.
Let`s put it together..
Restore '''Default.py''' and put your cursor between the quotes of the '''name area'''.
Type ‘ '''MOVIES''' ‘ and again with the '''url area''' this time restore '''test.py and copy, using Ctrl & c''', the
'''url=' http://www.tvdash.com/movies.html’''' text.
Go back to '''Default.py and paste using Ctrl&V''' between the single quotes in the '''url area'''.
'''addDir("MOVIES","http://www.tvdash.com/movies.html",1,"http://reggiebibbs.files.wordpress.com/2007/12/the-movies360-crop.jpg")'''
If you would like '''Xbmc''' to display a custom thumbnail for the '''MOVIES''' directory.
Put a url to an image or a path to an image,  inside the single quotes in the thumbnail area.
[[image:image10.jpg]]
The path should be on your xbox not your PC.
'''Q:/XBMC/PLUGINS/VIDEO/YOUR PLUGIN/IMAGES/Movie.png'''
Where Q:/ is a Directory of xbmc for xbox.
For other platforms use a Directory that you wish for your platform.
Or try :
<python>
translatePath(...)
    translatePath(path) -- Returns the translated path.
   
    path          : string or unicode - Path to format
   
    *Note, Only useful if you are coding for both Linux and the Xbox.
          e.g. Converts 'T:\script_data' -> '/home/user/XBMC/UserData/script_data'
          on Linux. Would return 'T:\script_data' on the Xbox.
   
    example:
      - fpath = xbmc.translatePath('T:\script_data')
</python>
So the previous.
'''addDir("MOVIES","http://www.tvdash.com/movies.html",1," http://reggiebibbs.files.wordpress.com/2007/12/the-movies360-crop.jpg")'''
Adds a '''directory folder''' named '''MOVIES''' to '''Xbmc''' with the url
'''http://www.tvdash.com/movies.html'''
moving to '''mode=1''' with the thumbnail
'''http://reggiebibbs.files.wordpress.com/2007/12/the-movies360-crop.jpg'''
Let`s move to '''mode=1 which is INDEX(url)'''
Go to '''test.py''' and copy the text between the single quotes of
'''match=re.compile(‘ ’)'''
Go to '''Default.py''' and delete the text between the match =re.compile(‘’) quotes and paste.
We now should have:
[[image:image11.jpg]]
<python>
for thumbnail,url,name in match:
                addDir(name,url,2,thumbnail)
</python>
Here we go, for every occurrence of the '''Tuple (thumbnail,url,name)''' found in '''match''' add the directory :-
'''MOVIE NAME, URL, MODE=2, THUMBNAIL  to Xbmc.'''
Lets go to '''mode=2''' which is '''VIDEOLINKS(url,name) :-'''
We are passing the '''Url and the name from the INDEX(url)''' - which only recieved the '''Url from CATEGORIES()'''
–  along to '''VIDEOLINKS (url,name)''' whatever lives in the brackets is passed along.
If you change this remember to change the mode area also !
Close Python shell to clear the shell page.
Restore '''test.py''' and restore your browser window.
'''Right click''' on the first movie link and '''Copy Link location.'''
[[image:image12.jpg]]
Before we move on it`s worth pointing out that nearly all video on websites is '''hidden or at least never just a direct link :'''
- '''http://tvdash.com/10_things_i_h8_aboutyou.flv'''
They will generally be hosted elsewhere by a provider such as:
'''Megavideo,  Tudou,  Youku,  Youtube,  Google,  Veoh.'''
They require a lot more handling than '''direct links''', but the routines are provided for you.
Rather than creating a '''class''' for you to import.
(Well I did, but this is a basic tutorial)
Just copy and paste them into '''Default.py''' as functions.
Paste the link into your restored browser address bar and press ENTER
[[image:image13.jpg]]
[[category:How To|Python Tutorial]]
[[category:Inner Workings]]
[[category:Python]]
[[Category:Plugins]]
[[category:Development]]
[[category:Skin Development]]
[[Category:Add-ons]]
[[Category:To-Do]]

Latest revision as of 02:50, 11 July 2020

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.