BartsideeTv Modules

Bart vd Ende edited this page Oct 27, 2013 · 25 revisions

Index

1 SETUP

Location:
All modules are located in the directory of the tv framework app.

You can find the framework directory in:

Windows: “C:\Users\[username]\AppData\Roaming\BOXEE\userdata\apps\bartsidee.tv”
Linux: “/home/[username]/.boxee/UserData/apps/bartsidee.tv”
MAC: “[username]/Library/Application Support/Boxee/userdata/apps/bartsidee.tv”

Make sure you have opened the app at least one time in boxee so that the files are downloaded!

Now in the homedir of the app you can find a directory

‘modules’

inside this directory you will find all the modules installed at that moment.

Debug mode
I have included a debug mode in the framework so you can more easily test the modules and read out errors. It is important to set debug mode to ‘True’ when developing modules. You have to edit main.py in the libs directory (bartsidee.tv/libs/main.py) in the first few lines of the python file you will find the variable ‘self.debug’. Change it value to ‘True’ to enable local module development and a better error logging in the main boxee log.

It is important to set this value correctly as it will set BartsideeTv to local mode. If it remains on False it will clean/remove all modules not listed in the online database!

As a tip you can use the python ‘print’ command to log variables to the main boxee log to ease debugging. For example print str(“This is an test”) or print variable will print the content in the boxee log.

Adding a module
If you want to add a module, please start by adding a new directory to the ‘modules’ folder. When you do this please give the directory a name with only lowercase letters and no special characters or spaces! Since the latest version of the framework yo also have to add a version number to the module directory. (example the module ‘youtube’ gets a folder name ‘youtube-1′) The directory name will be used as an internal id for the framework.

Now add 3 files to this new directory:

1. image file  "example.png"
2. python file "example.py"
3. python file "__init__.py"

Make sure you give both the python file and the image file the same name as the directory name for your module. For example if the directory name of the module is called ‘youtube’ the files inside this module should be called ‘youtube.py’ and ‘youtube.png’.

Image file
The image file included should be a ‘png’ image file and preferably a 200px by 200px image saved 24-bit png with transparency enabled.

Python file
All module file should have the same basic template to make sure it can communicate with the framework. When you start building a new module you can start with a template seen below you can also download it from the tools dir as "template.py".

import mc, re, os, sys
sys.path.append(os.path.join(mc.GetApp().GetAppDir(), 'libs'))
import ba
from beautifulsoup.BeautifulSoup import BeautifulSoup

class Module(object):
    def __init__(self):
        self.name = "Module Name"                   #Name of the channel
        self.type = ['search','genre','list']       #Choose between 'search', 'list', 'genre'
        self.episode = True                         #True if the list has episodes
        self.filter = []                            #Option to set a filter to the list
        self.genre = []                             #Array to add a genres to the genre section
        self.content_type = 'video/x-ms-asf'        #Mime type of the content to be played
        self.country = 'NL'                         #2 character country id code

    def Search(self, search):
        """Start your code here"""

        """End your code here"""
        return streamlist

    def List(self):
        """Start your code here"""

        """End your code here"""
        return streamlist

    def Episode(self, stream_name, stream_id, page, totalpage):
        """Start your code here"""

        """End your code here"""
        return episodelist

    def Genre(self, genre, filter, page, totalpage):
        """Start your code here"""

        """End your code here"""
        return genrelist

    def Play(self, stream_name, stream_id, subtitle):
         """Start your code here"""

        """End your code here"""
        return play

Python IDE
Watch out with editing python files in a text editors. Python is a bit picky on iterations and a script can fail very quickly on not setting a tab or space correct. In fact python does not support tabs at all.

2 Module Architecture

2.1 Import

As you can see from the template in the setup section the python file is actually an python object with several functions in it. The BartsideeTV Framework will call these functions when collecting specific data.

Lets start with the top part:

import mc, re, os, sys
sys.path.append(os.path.join(mc.GetApp().GetAppDir(), ‘libs’))
import ba
from beautifulsoup.BeautifulSoup import BeautifulSoup

This is pretty straightforward if you are familiar with python, the import section will import external function to be used in the script. In this case:

import mc, re, os, sys
sys.path.append(os.path.join(mc.GetApp().GetAppDir(), ‘libs’))

…will import some basic python functions, sets the python path correct and loads the boxee api.

import ba

…wll import the BartsideeTV framework specific functions

from beautifulsoup.BeautifulSoup import BeautifulSoup

…will load the beatifulsoup html and xml parser. This is very useful as its converts html/xml code to objects thus removing the need for lots of regex code. It will also convert the html to unicode so you don’t have to worry about text encoding.

You can add other import functions as you like, some examples that will be useful are:

from urllib import quote_plus  #url encode text strings, handy for passing the search parameter
import datetime, time  #can generate, convert and calculate dates and time
import md5 #can encode md5 strings
import base64 #can encode/encode base64 strings
import simplejson as json #json parser
from itertools import izip #iterate over multiple arrays the same time
import yql #pretty nifty module that let you do sql searches on the web

2.2 Init

The module object contains several function, the init function is a native python function that is automatically loaded when the object is initiated. For the BartsideeTV Framework it contains some basic variables that will tell the framework how to handle functions in the module. The fixed variables (from the template) should be present in the init function to make to module work probably. Important to notice is that the init variables are global and can be called from anywhere in the module script.

I will try to explain a bit more what the variables are for:

self.name = "Module Name"

…will state the module name. Please do not use special characters, but spaces and capital letters are allowed.

self.type = [‘search’,‘genre’,‘list’]

…will tell the framework which functions in the module are available. There are 3 possible options to choose from: search: This will add a dynamic search option to the module list: This will add a static list option to the module genre: This will add a static list option with genres to the module

Please note that the ‘search’ type is only for dynamic searching. In this case you directly scrape the search results from a webpage. If you have a static list of streams a search option will be automatically added and you will only need the ‘list’ type. If you enable a type by putting it in the variable you must be sure to also script to appropriate module function named by the same name. So if you at the ‘list’ type be sure to script also the self.List() function

self.episode = True

…"True/False" when set to true it will open the episode window after selecting a stream. Stream variables are passed to the self.Episode() function. When using live tv streams please turn this option off.

self.filter = []

…will add a filter option to the genre section. Add string variables in array formation here like ['channel1', 'channel2'] etc. You have to make sure you add a specific filter to the genre stream list to make sure it is working

self.genre = []

…will add the main genres to the genre functions. Add string variables in array formation here like ['drama', 'action'] etc. The genre parameter is forwarded to the genre function so you can scrape the correct list for a specific genre.

self.content_type = ‘video/x-ms-asf’

…will give the boxee player information about the content to be played, Please use a correct mime type. When you use the flash mime type ‘video/x-flv’ the stream will be opened in the boxee browser.

self.country = ‘UK’

.. will give the user information regarding to module and stream origin. If the streams are not available for him in his country he can easily disable it.

You can add custom global variables or specific function to be initiated on load after the framework variables

2.3 Search

The search function will give you the possibility to do a dynamic search a a specific page.

You have to understand there are 2 ways of searching in the framework. 1 a dynamic search 2 a static list. A dynamic search ‘plugs-into’ a searchengine of a other site and fetches the results. A static list just scrapes a simple static stream lists from a website or array. See also the chapter list.

To enable the dynamic search function use the starting code below and make sure you add ‘search’ to the self.type variable in the general module configuration. See also the init section.

def Search(self, search):
    """Start your code here"""

    """End your code here"""
    return streamlist

Receiving variables:

Variable Type Description
search string Contains the search request from the user

The basic construction is that the search function passes a variable ‘search’ to the script that is requested by the user and that it expects back an object ‘streamlist‘ with results.

The ‘search’ variable passed to the function is not escaped so please use the quote_plus(…) function to escape the characters. See the import section for more information.

To return the stream list in the correct way the frameworks expects the returned information in a specific output. A single stream should be put into an object and the array of streams should be put in a list. An example of such an configuration is:

streamlist = list()
for item in VarA:
    stream = ba.CreateStream()
    stream.SetName(item[0])
    stream.SetId(item[1])
    streamlist.append(stream)
return streamlist

Explanation of the code:

streamlist = list()

The streamlist is set as list variabel

for item in VarA:

A loop is started iterating the array ‘VarA’

stream = ba.CreateStream()

An instance is created for the stream item

stream.SetName(item[0])

The SetName variable will give the stream its visible name in the app. Passing the variable item[0] to it in this case.

stream.SetId(item[1])

The SetId variable will give the stream its id parameter, this will be passed to the episode function or directly to the boxee player if there are no episodes. It can be a path or a id to be processed later. The content should be set as string. Passing the variable item[1] to it in this case.

streamlist.append(stream)

Appending the instance to the end of the streamlist list.

return streamlist

returning the streamlist list to the framework

WARNING: as this function is directly called from the search window and is not cached in any way it can have dramatic influence in the speed the results are returned to the user. Therefor keep this function small and not process intensive code.

Example:

def Search(self, search):
    url = ‘http://suggestqueries.google.com/complete/search?client=youtube&jsonp=yt&q=’ + quote_plus(search)
    data = ba.FetchUrl(url, 0)
    data = re.compile(‘yt\((.*?)\)$’, re.DOTALL + re.IGNORECASE).search(data).group(1)
    json_data = json.loads(data)

    streamlist = list()
    for info in json_data[1]:
        stream = ba.CreateStream()
        stream.SetName(info[0])
        stream.SetId(info[0])
        streamlist.append(stream)

    return streamlist

2.4 List

The list function will allow you the specify a static list of streams.

You have to understand there are 2 ways of searching in the framework. 1 a dynamic search 2 a static list. A dynamic search ‘plugs-into’ a search engine of a other site and fetches the results. A static list just scrapes a simple static stream lists from a website or array. See also the chapter search.

To enable the list function use the starting code below and make sure you add ‘list’ to the self.type variable in the general module configuration. See also the init section.

def List(self):
    """Start your code here"""

    """End your code here"""
    return streamlist

Receiving variables:

Variable Type Description
- - -

A static list can be specified as a list of stream urls directly put into the module script or it can be scraped from a website. The list script is called once every 3 days when activated to update the variables and store the data into the framework database.

To return the streamlist in the correct way the frameworks expects the returned information in a specific output. A single stream should be put into an object and the array of streams should be put in a list. An example of such an configuration is:

streamlist = list()
for item in VarA:
    stream = ba.CreateStream()
    stream.SetName(item[0])
    stream.SetId(item[1])
    streamlist.append(stream)
return streamlist

Explanation of the code:

streamlist = list()

The streamlist is set as list variabel

for item in VarA:

A loop is started iterating the array ‘VarA’

stream = ba.CreateStream()

An instance is created for the stream item

stream.SetName(item[0])

The SetName variable will give the stream its visible name in the app. Passing the variable item[0] to it in this case.

stream.SetId(item[1])

The SetId variable will give the stream its id parameter, this will be passed to the episode function or directly to the boxee player if there are no episodes. It can be a path or a id to be processed later. The content should be set as string. Passing the variable item[1] to it in this case.

streamlist.append(stream)

Appending the instance to the end of the streamlist list.

return streamlist

returning the streamlist list to the framework

Scraping Example:

def List(self):
    url = "www.example.com/a-z"
    data = ba.FetchUrl(url)
    soup = BeautifulSoup(data, convertEntities="xml", smartQuotesTo="xml")

    div_main  = soup.findAll( ‘div’, {‘class’ : ‘mo-a alphabetical’})[0]
    div_show  = div_main.findAll( ‘div’, {‘class’ : ‘wrapper’})[0]

    streamlist = list()
    for info in div_show.findAll(‘a’):
        stream = ba.CreateStream()
        name = info.contents[0]
        id = self.url_base + info[‘href’]
        if not name in self.exclude:
            stream.SetName(name)
            stream.SetId(id)
            streamlist.append(stream)

    return streamlist

Direct play Example:

def List(self):
    channels = [
        ["101 TV", "%s/npo/101tv-%s"],
        ["Best 24", "%s/npo/best24-%s"],
        ["Consumenten 24", "%s/npo/consumenten24-%s"],
        ["Cultura 24", "%s/npo/cultura24-%s"],
        ["Familie 24 / Z@ppelin", "%s/npo/familie24-%s"],
        ["Geschiedenis 24", "%s/npo/geschiedenis24-%s"],
        ["Holland Doc 24", "%s/npo/hollanddoc24-%s"],
        ["Humor TV 24", "%s/npo/humortv24-%s"],
        ["Journaal 24", "%s/nos/journaal24-%s"],
        ["Politiek 24", "%s/nos/politiek24-%s"],
        ["Spirit 24", "%s/npo/spirit24-%s"],
        ["Sterren 24", "%s/npo/sterren24-%s"]
    ]
            streamlist = list()
    for item in channels:
        stream = ba.CreateStream()
        stream.SetName(item[0])
        stream.SetId(item[1])
        streamlist.append(stream)

    return streamlist

2.5 Episode

The Episode function will allow you to scrape a detailed episode page if you specify episode ‘true’ in the init section.

def Episode(self, stream_name, stream_id, page, totalpage):
    """Start your code here"""

    """End your code here"""
    return episodelist

Receiving variables:

Variable Type Description
stream_name string Contains the name of the stream
stream_id string Contains the id of the stream
page string Returns the current page
totalpage string Returns the total of pages

If this function is specified and set probably in the init configuration the framework will call this function after the users has selected an item from the ‘list‘ or ‘search‘ function. The variables stream_name and stream_id are passed in te state they where set in the function ‘search’ or ‘list’. You can fetch extra episode information, like episode number, serie number and/or a thumb to the episode list specified as output.

There is an option to specify a control to browse multiple pages, this can be handy if the episode list is very long (enhance speed) or spread over multiple web pages. The page variable will give the current requested page from the user with a number as string with the default of 1. The total page number will give a string variable with the total number of pages available, default is set to 1. You don’t need to specify the totalpage and page string if you don’t need it.

To return the path information in the correct way the frameworks expects the returned information in a specific output. A single episode item should be put into an object and the array of episodes should be put in a list. An example of such an configuration is:

episodelist = list()
    for item in VarA:
        episode = ba.CreateEpisode()
        episode.SetName(item.title)
        episode.SetId(item.path)
        episode.SetDescription(item.desc)
        episode.SetThumbnails(item.thumb)
        episode.SetDate(item.pup)
        episode.SetPage(page)
        episode.SetTotalpage(totalpage)
        episodelist.append(episode)

    return episodelist

Explanation of the code:

episodelist = list()

The episodelist is set as list variabe

for item in VarA:

A loop is started iterating the array ‘VarA’

episode = ba.CreateEpisode()

An instance is created for the episode item

episode.SetName(item.title)

The SetName variable will give the stream its visible name in the app. Passing the variable item.title to it in this case.

episode.SetId(item.path)

The SetId variable will give the stream its id parameter, this will be passed to play function. It can be a path or a id to be processed later. The content should be set as string. Passing the variable item.path to it in this case.

episode.SetDescription(item.desc)

The SetDescription variable will give the stream its visible description in the app. Passing the variable item.desc to it in this case.

episode.SetThumbnails(item.thumb)

The SetThumbnails variable will give the stream its visible thumbnail in the app. Passing the variable with path item.thumb to it in this case.

episode.SetDate(item.pup)

The SetDat variable will give the stream its visible date in the app, you can also pass other info in this string for example the episode number. Passing the variable item.pup to it in this case.

episode.SetPage(page)

The SetPage variable will pass the current page number to the framework, only needed if you use multiple pages. Passing the variable page to it in this case.

episode.SetTotalpage(totalpage)

The SetTotalpage variable will pass the total number of pages to the framework, only needed if you use multiple pages. Passing the variable totalpage to it in this case.

episodelist.append(episode)

Appending the instance to the end of the episodelist list.

return episodelist

returning the episodelist list to the framework

Multipage Example:

def Episode(self, stream_name, stream_id, page, totalpage):
    url = str(stream_id) + ‘/page=’ + str(page)
    data = ba.FetchUrl(url, 3600)

    if data == "":
        mc.ShowDialogNotification("Geen afleveringen gevonden voor " + str(stream_name))
        return

    soup = BeautifulSoup(data, convertEntities="xml", smartQuotesTo="xml")

    if totalpage == "":
        try:
            pages = soup.findAll( ‘div’, {‘class’ : ‘paginator’})[0]
            pages = pages.findAll(‘span’)
            totalpage = len(pages) – 1
        except:
            totalpage = 1

    div_main = soup.findAll(‘div’, {‘class’ : ‘mo-c double’})[0]
    div_show = div_main.findAll(‘div’, {‘class’ : ‘wrapper’})[0]

    info = div_show.findAll(‘div’, {‘class’ : ‘thumb’})
    airtime = div_show.findAll(‘div’, {‘class’ : ‘airtime’})

    episodelist = list()
    for info_i, airtime_i in izip(info, airtime):
        episode = ba.CreateEpisode()
        episode.SetName(stream_name)
        episode.SetId(self.url_base + info_i.a[‘href’])
        episode.SetThumbnails(self.url_base + info_i.find(‘img’)[‘src’])
        episode.SetDate(airtime_i.a.span.contents[0])
        episode.SetPage(page)
        episode.SetTotalpage(totalpage)
        episodelist.append(episode)

    return episodelist

Single page Example:

def Episode(self, stream_name, stream_id, page, totalpage):
    url = self.url_base + ‘/iplayer/search?q=’ + quote_plus(stream_id)
    data = ba.FetchUrl(url, 3600)

    if data == "":
        mc.ShowDialogNotification("No episode found for " + str(stream_name))
        episodelist = list()
        return episodelist

    soup = BeautifulSoup(data, convertEntities="xml", smartQuotesTo="xml")

    div_show = soup.find( ‘ul’, {‘class’ : ‘result-list listview episodelist’})

    episodelist = list()
    for info in div_show.findAll(lambda tag: tag.name == ‘li’ and not tag.attrs) + div_show.findAll(‘li’,{‘class’:‘audio’}):
        link = info.findAll(‘a’)
        if len(link) > 1:
            title = link[1][‘title’].split(‘: ‘)
            if len(title) > 2:
                date = title[2]
            else:
                date = ”
            episode = ba.CreateEpisode()
            episode.SetName(title[0])
            episode.SetId(self.url_base + link[1][‘href’])
            episode.SetDescription(str(info.find(‘p’, {‘class’:‘additional’}).contents[0] + ‘ – ‘ + info.find(‘p’, {‘class’:‘episode-synopsis’}).contents[0]).replace(‘\n‘,”).replace(‘\t‘,”))
            episode.SetThumbnails(str(link[0].img[‘src’][:-11] + "_314_176.jpg"))
            episode.SetDate(date)
            episode.SetPage(page)
            episode.SetTotalpage(totalpage)
            episodelist.append(episode)

    return episodelist

2.6 Genre

The genre function will allow you the specify a genre list of streams. The genrelist is not search able or indexable at the moment.

To enable the genre function use the starting code below and make sure you add ‘genre’ to the self.type variable in the general module configuration and specify genre variables to the self.genre list. See also the init section.

 def Genre(self, genre, filter, page, totalpage):
     """Start your code here"""

     """End your code here"""
    return genrelist

Receiving variables:

Variable Type Description
genre string Contains the genre string passed from the user
filter string Contains the filter string passed from the user
page string Returns the current page
totalpage string Returns the total of pages

If this function is specified and set probably in the init configuration it will be acceable from the module section in the framework. The genre sections allows you to specify stream list with a specific genre. You can also specify for example a date as genre. As extra you can filter a genre list if you fill in the self.filter list in the init section. A filter should be in this case also specified with every stream.

There is an option to specify a control to browse multiple pages, this can be handy if the episode list is very long (enhance speed) or spread over multiple web pages. The page variable will give the current requested page from the user with a number as string with the default of 1. The total page number will give a string variable with the total number of pages available, default is set to 1. You don’t need to specify the totalpage and page string if you don’t need it.

To return the path information in the correct way the frameworks expects the returned information in a specific output. A single stream item should be put into an object and the array of stream should be put in a list. An example of such an configuration is:

 genrelist = list()
 for item in VarA:
            genreitem = ba.CreateEpisode()
            genreitem.SetName(item.title)
            genreitem.SetId(item.path)
            genreitem.SetDescription(item.desc)
            genreitem.SetThumbnails(item.thumb)
            genreitem.SetDate(item.date)
            genreitem.SetFilter(item.filter)
            genreitem.SetPage(page)
            genreitem.SetTotalpage(totalpage)
            genrelist.append(genreitem)

Explanation of the code:

genrelist = list()

The genrelist is set as list variabe

for item in VarA:

A loop is started iterating the array ‘VarA’

genre = ba.CreateEpisode()

An instance is created for the episode item

genre.SetName(item.title)

The SetName variable will give the stream its visible name in the app. Passing the variable item.title to it in this case.

genre.SetId(item.path)

The SetId variable will give the stream its id parameter, this will be passed to play function. It can be a path or a id to be processed later. The content should be set as string. Passing the variable item.path to it in this case.

genre.SetDescription(item.desc)

The SetDescription variable will give the stream its visible description in the app. Passing the variable item.desc to it in this case.

genre.SetThumbnails(item.thumb)

The SetThumbnails variable will give the stream its visible thumbnail in the app. Passing the variable with path item.thumb to it in this case.

genre.SetDate(item.date)

The SetDat variable will give the stream its visible date in the app, you can also pass other info in this string for example the episode number. Passing the variable item.date to it in this case.

genre.SetFilter(item.filter)

The SetFilter variable will give the stream its filter variable in the app, if the user presses a filter (set in self.filter) the fra work will only show the streams that have the same filter id specified. Passing the variable item.filter to it in this case.

genre.SetPage(page)

The SetPage variable will pass the current page number to the framework, only needed if you use multiple pages. Passing the variable page to it in this case.

genre.SetTotalpage(totalpage)

The SetTotalpage variable will pass the total number of pages to the framework, only needed if you use multiple pages. Passing the variable totalpage to it in this case.

genre.append(episode)

Appending the instance to the end of the episodelist list.

return genrelist

returning the genrelist list to the framework

Multipage Example:

def Genre(self, genre, filter, page, totalpage):
    url = self.url_base + ‘/iplayer/tv/categories/’ + self.genre_links[genre] + ‘?sort=dateavailable&page=’ + str(page)
    data = ba.FetchUrl(url, 3600)

    if data == "":
        mc.ShowDialogNotification("No episode found for " + str(genre))
        genrelist = list()
        return genrelist

    soup = BeautifulSoup(data, convertEntities="xml", smartQuotesTo="xml")

    if totalpage == "":
        try:
            pagediv = soup.findAll( ‘div’, {‘class’ : ‘pagination-control’})[0]
            apage = pagediv.findAll("li")
            totalpage = int(len(apage))
        except:
            totalpage = 1


    div_show = soup.find( ‘ul’, {‘class’ : ‘listview episodelist’})

    genrelist = list()
    for info in div_show.findAll(lambda tag: tag.name == ‘li’ and not tag.attrs) + div_show.findAll(‘li’,{‘class’:‘multi-episode’}):
        link = info.findAll(‘a’)

        if len(link) > 1:
            title = link[1][‘title’].split(‘: ‘)
            if len(title) > 1:
                filters = title[1]
                if len(title) > 2:
                    date = title[2]
                else:
                    date = ”
            else:
                filters = ”
            genreitem = ba.CreateEpisode()
            genreitem.SetName(title[0])
            genreitem.SetId(self.url_base + link[1][‘href’])
            genreitem.SetDescription(str(info.find(‘p’, {‘class’:‘episode-synopsis’}).contents[0]).replace(‘\n‘,”).replace(‘\t‘,”))
            genreitem.SetThumbnails(str(link[0].img[‘src’][:-11] + "_314_176.jpg"))
            genreitem.SetDate(filters)
            genreitem.SetFilter(date)
            genreitem.SetPage(page)
            genreitem.SetTotalpage(totalpage)
            genrelist.append(genreitem)

    return genrelist

Multipage 2 Example:

def Genre(self, genre, filter, page, totalpage):
    url = self.url_base + ‘/7dagen/’ + genre
    if filter != "": url = url + ‘,’ + str(filter)
    url = url + ‘?weergave=detail&page=’ + str(page)
    data = ba.FetchUrl(url, 3600)
    if data == "":
        mc.ShowDialogNotification("No genre found for " + str(genre))
        genrelist = list()
        return genrelist
    soup = BeautifulSoup(data, convertEntities="xml", smartQuotesTo="xml")
    if totalpage == "":
        try:
            pagediv = soup.findAll( ‘div’, {‘class’ : ‘pagination’})[0]
            apage = pagediv.findAll("a")
            totalpage = int(apage[len(apage)-2].contents[0])
        except:
            totalpage = 1

    div_show = soup.find( ‘table’, {‘class’ : ‘broadcasts detail’})

    genrelist = list()
    for info in div_show.findAll("tr"):
        omroep = info.findAll(attrs={"class" : "broadcaster-logo"})[0][‘alt’]
        if omroep == "Nederland 1": omroep = "nl1"
        elif omroep == "Nederland 2": omroep = "nl2"
        elif omroep == "Nederland 3": omroep = "nl3"
        try:
            thumb = info.findAll(attrs={"class" : "thumbnail"})[0][‘src’]
        except:
            thumb = info.findAll(attrs={"class" : "thumbnail placeholder"})[0][‘src’]
        path = self.url_base + info.find(attrs={"class" : "thumbnail_wrapper"})[‘href’]
        date = info.find(attrs={"class" : "time"}).time.contents[0].replace(‘ ‘,”).replace(‘\n‘,”).replace(‘\t‘,”)
        title = info.findAll(attrs={"class" : "series"})[0].contents[0]
        desc = info.find(‘div’, {‘class’ : ‘description’}).p.contents[0]

        genreitem = ba.CreateEpisode()
        genreitem.SetName(title)
        genreitem.SetId(path)
        genreitem.SetDescription(desc)
        genreitem.SetThumbnails(thumb)
        genreitem.SetDate(date)
        genreitem.SetFilter(str(omroep).upper())
        genreitem.SetPage(page)
        genreitem.SetTotalpage(totalpage)
        genrelist.append(genreitem)

    return genrelist

2.7 Play

The play function will allow you to do some post processing if an item should be played. The stream_id variable is passed from the episode, list or search function an can be manipulated. For example scraping the streaming path of a specific page. You can also pass the stream_id directly to the player if you want, make sure you setup the function in the corresponding way. There is also a possibility to add a subtitle if available.

def Play(self, stream_name, stream_id, subtitle):
    """Start your code here"""

    """End your code here"""
    return play

Receiving variables:

Variable Type Description
stream_name string Contains the name of the stream
stream_id string Contains the id of the stream
subtitle Boolean Returns the user setting for subtitles

To return the path information in the correct way the frameworks expects the returned information in a specific output. There can only be returned one stream item at once, so no lists. An example of such an configuration is:

play = ba.CreatePlay()
play.SetPath(streampath)

#Optional
if subtitle:
   play.SetSubtitle(subtitlepath)
   play.SetSubtitle_type(string)

return play

Explanation of the code:

play = ba.CreatePlay()

An instance is created for the stream item

play.SetPath(streampath)

The SetPath variable will set the path to be played by the boxee player.

return play

Returning the play object to the framework

Optional:

if subtitle:

Checks if the user has enabled subtitles

play.SetSubtitle(subtitlepath)

Add a subtitle path to the stream, make sure boxee supports it.

play.SetSubtitle_type(string)

Only applicable on sami subtitles. Boxee has problems with them and when setting SetSubtitle_type to ‘sami’ the framework will automatically converts and passes the subtitle to a temporary srt subtitle file.

Static Example Flash:

def Play(self, stream_name, stream_id, subtitle):

    play = ba.CreatePlay()
    play.SetPath(stream_id)
    play.SetDomain(‘youtube.com’)
    play.SetJSactions(”)

    return play

Scrape Example:

def Play(self, stream_name, stream_id, subtitle):
    data = ba.FetchUrl(stream_id)
    url_play = re.compile(‘<a class="wmv-player-holder" href="(.*?)"></a>’, re.DOTALL + re.IGNORECASE).search(data).group(1)

    play = ba.CreatePlay()
    play.SetPath(url_play)

    return play

2.8 General Functions

There are several general function available in the framework. A short overview below:

Fetch an Url

ba.FetchUrl(url, cacheTime, xhr, params)

A function to get a http request, so you can fetch the html content of a specific website. It has the option to cache the results to release the load on internet servers. If the variable cachetime is set it will automatically loads the page from the cache instead of the internet as long as the cache is not expired yet. It is using a GET request on default.

Note that the caching of a page speeds up the loading time, but also is adding information to the database and extending the disk usage. For boxee 0.9 users this is no problem but the boxee box has a limited amount of space available. So please use the cache function appropriate.

Passing variables:

Variable Type Description Needed
url string The path to the website Yes
cacheTime integer Time period to keep the http data in cache (in seconds) No
xhr Boolean Send the request as ajax xhr No
params string Use POST request with params (var=test&var2=test2) No

Examples:

# GET request
path = "http://www.google.com"
data = ba.FetchUrl(path)

# GET request with params
path = "http://www.google.com?search=boxee&var=delta"
data = ba.FetchUrl(path)

# GET request cached for 60 minutes
path = "http://www.google.com"
data = ba.FetchUrl(path, 3600)

# XHR ajax call not cached
path = "http://www.google.com"
data = ba.FetchUrl(path, 0, True)

# POST Request not cached
path = "http://www.google.com"
params = "search=boxee&var=delta"
data = ba.FetchUrl(path, 0, False, params)

# POST Request cached for 5 minutes
path = "http://www.google.com"
params = "search=boxee&var=delta"
data = ba.FetchUrl(path, 300, False, params)

Set User Agent

ba.UserAgent(var):

A function to set the user agent of the http requests

Passing variables:

Variable Type Description Needed
var string User agent string Yes

BeautifulSoup

BeautifulSoup(data):

A very usefull parser to parse xml or html data. It transforms the string into variables that can be searched or called. For more information regarding BeautifulSoup please read the manual on crummy.com

Main variables:

Variable Type Description Needed
data string A string with html / xml data Yes

Examples:

doc = [‘<html><head><title>Page title</title></head>’,
       ‘<body><p id="firstpara" align="center">This is paragraph <b>one</b></p>’,
       ‘<p id="secondpara" align="blah">This is paragraph <b>two</b></p></body>’,
       ‘</html>’]
soup = BeautifulSoup(”.join(doc))

soup.head.title
# <title>Page title</title>

soup.body.p.b.string
# u’one’

soup.findAll([‘title’, ‘p’])
# [<title>Page title</title>,
#  <p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,
#  <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]

#####
doc = [‘<html><head><title>Page title</title></head>’,
       ‘<body><p id="firstpara" align="center">This is paragraph <b>one</b></p>’,
       ‘<p id="secondpara" align="blah">This is paragraph <b>two</b></p></body>’,
       ‘</html>’]
soup = BeautifulSoup(”.join(doc))

for info in soup.findAll(‘p’):
# create your boxee list at this point and extract data from the p tag
# example info.b.contents[0] will result in ‘one’ and in the second list in ‘two’