Results 1 to 8 of 8
  1. #1
    Administrator
    Join Date
    Sep 2013
    Posts
    84

    [iStream Guide - Dev Only] Write your own Sources and Indexers

    iStream supports plugin architecture that allows other XBMC community developers to add sources and indexers to iStream.

    iStream takes care of all the major features like subscriptions, xbmc integration, favorites, bookmarks, autoplay etc. and provides an easy to use extensible architecture, that any developer can utilize to add sources and indexers.

    This guide assumes that you have basic understanding of:
    • Python
    • Creating and Maintaing XBMC Repository
    • Coding an XBMC Addon


    Download the dummy iStream Extension Addon from here: iStreamDummyAddon

    1. Setting up an XBMC Addon for iStream extension

    2. Code a Source (Movie or TV Source) for iStream

    3. Code an Indexer for iStream

    4. iStream Helper functions

    TO ALL DEVS: Please follow the guide, write and share your sources and indexers in the subforum: iStream Extensions...Help us improve the guide along the way.

    NOW EVERYONE CAN CONTRIBUTE TO ISTREAM

  2. #2
    Administrator
    Join Date
    Sep 2013
    Posts
    84
    Setting up an XBMC Addon for iStream extension

    1. Create the XBMC addon directory of the format script.icechannel.extn.[MY-iStream-Extension]; where [MY-iStream-Extension] is to be replaced with your unique identifier. For the rest of the tutorial I will use script.icechannel.extn.tutorial as an example.

    2. Create addon.xml file in the above directory. Addon.xml should contain the following.
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <addon id="script.icechannel.extn.tutorial" version="0.0.1" name="iStream Extension Tutorial" provider-name="iStream">
     <requires>
      <import addon="xbmc.python" version="2.1.0"/>
     </requires>
     <extension library="default.py" point="xbmc.service" />
     <extension point="xbmc.addon.metadata">
      <summary lang="en">iStream Extension Tutorial</summary>
      <description lang="en">iStream Extension Tutorial</description>
      <platform></platform>
      <language></language>
      <license></license>
      <forum></forum>
      <website></website>
      <source></source>
      <email></email>
     </extension>
    </addon>
    3. Create a file default.py with the following.
    Code:
    # default.py
    addon_id="script.icechannel.extn.tutorial"
    addon_name="iStream Extension Tutorial"
    4. Create a directory: plugins.

    5. Inside the plugins directory, create two directories:
    - sources: code for your sources goes in this directory.
    - indexers: code for your indexers goes in this directory.

    If you want to keep your sources and indexers in same directory, create just one directory under plugins:
    - tvandmovies: code for sources and indexers goes in here, if you want to keep them together.

    The name of the directory inside plugins do not matter, it can be anything. The only purpose is so that developers can organize their work accordingly. You can even have directories like HDSources, SDSources etc. inside plugins.

    Your directory structure is now completely ready for iStream Extension. You can drop as many sources and/or indexer inside the sub-directories under the plugins directory as you want.

    You should now have following directory structure as follows:
    Code:
      /script.icechannel.extn.tutorial/
      /script.icechannel.extn.tutorial/addon.xml
      /script.icechannel.extn.tutorial/default.py
      /script.icechannel.extn.tutorial/plugins/
      /script.icechannel.extn.tutorial/plugins/tvandmovies/
    All the sources and indexers "*.py" files will go in: /script.icechannel.extn.tutorial/plugins/tvandmovies/

  3. #3
    Administrator
    Join Date
    Sep 2013
    Posts
    84
    Code a Source (Movie or TV Source) for iStream

    1. Follow the steps in post#2 of this thread: Setting up an XBMC Addon for iStream extension; before you continue.

    2. Create the file: myfirstsource.py under directory: /script.icechannel.extn.tutorial/plugins/tvandmovies/

    3. Add the following imports to myfirstsource.py
    Code:
    from entertainment.plugnplay import Plugin
    from entertainment import common
    4. Add following imports as you need them
    - if TV Source, Add: from entertainment.plugnplay.interfaces import TVShowSource
    - if Movie Source, Add: from entertainment.plugnplay.interfaces import MovieSource
    - if both TV and Movie Source, Add both the above imports.

    For this example we assume that the source is for both TV and Movies. The rest of the code in this tutorial will also follow this assumption:
    Code:
    from entertainment.plugnplay.interfaces import TVShowSource
     from entertainment.plugnplay.interfaces import MovieSource
    5. Define your source class. Make sure the the name of the file and the name of class is same. Since our filename is myfirstsource.py, our class should be myfirstsource. Also, since we are coding a Movie and TV source, the code should look like as follows.
    Code:
    class myfirstsource(MovieSource, TVShowSource):
         implements = [MovieSource, TVShowSource]
    				
         name = "MyFirstSource" #unique name for the addon
         display_name = "My First Source" #display name for the addon
         base_url = 'http://myfirstsource.tv' #base_url of the source site

    6. define GetFileHostsForContent function in the class.

    The signature and parameter details of the function are as follows:
    def GetFileHostsForContent(self, title, name, year, season, episode, type, list, lock, message_queue)
    - title: Title of the movie with year or title of the tv-episode
    - name: Movie or tv show name
    - year: release year
    - season: tv season number
    - episode: tv episode number
    - type: possible values: movies or tv_episodes
    - list: the list, that the hosts will be appended to
    - lock: ignore for now
    - message_queue: ignore for now

    In this function, the developer should search the website for:
    - the movie: if type==movies, using name and year of the movie OR
    - the tv episode: if type==tv_episodes, using name, year of the show an season + episode number

    A successful search would result in a url that has the hosters for the item. This url is then passed to GetFileHosts function of the class.

    The code of this function would look something like this:

    Code:
      def GetFileHostsForContent(self, title, name, year, season, episode, type, list, lock, message_queue):
        from entertainment.net import Net
        net = Net()
        
        title = self.CleanTextForSearch(title) 
        name = self.CleanTextForSearch(name)    
    
        # write the code to search the source website for the page containing hosters
        # store the page url in the variable url
        ...
        ...
        # url
    
        self.GetFileHosts(url, list, lock, message_queue)

    7. define GetFileHosts function in the class.

    The signature and parameter details of the function are as follows:
    def GetFileHosts(self, url, list, lock, message_queue)
    This function is called by GetFileHostsForContent, to fetch the hosters from the url.
    - url: the url identified in GetFileHostsForContent function
    - list: passed from GetFileHostsForContent; the list, that the hosts will be appended to
    - lock: passed from GetFileHostsForContent; ignore for now
    - message_queue: passed from GetFileHostsForContent; ignore for now

    This function is to extract the host, the host url, and quality information from the url provided.
    For each host and/or host_url extracted call the following in the base class.
    self.AddFileHost(list, quality, host_url)

    The code here would look something like this:

    Code:
      def GetFileHosts(self, url, list, lock, message_queue):
        import re
    
        from entertainment.net import Net
        net = Net()
    
        # write the code here to open the url provided
        # then find the host links and quality of the links on the page
        # then for each of the host link call
        ...
        ...
        for ... :
          self.AddFileHost(list, quality, host_url)

    The entire code file would look something like this:
    Code:
    # file: myfirstsource.py
    # location: /script.icechannel.extn.tutorial/plugins/tvandmovies/
    
    from entertainment.plugnplay import Plugin
    from entertainment import common
    
    from entertainment.plugnplay.interfaces import TVShowSource
    from entertainment.plugnplay.interfaces import MovieSource
    
    class myfirstsource(MovieSource, TVShowSource):
        implements = [MovieSource, TVShowSource]
    				
        name = "MyFirstSource"
        display_name = "My First Source"
        base_url = 'http://myfirstsource.tv' #base_url of the source site
        
        def GetFileHosts(self, url, list, lock, message_queue):
            import re
    
            from entertainment.net import Net
            net = Net()
    
            # write the code here to open the url provided
            # then find the host links and quality of the links on the page
            # then for each of the host link call
            #...
            #...
            #for ... :
                #self.AddFileHost(list, quality, host_url)
    
        def GetFileHostsForContent(self, title, name, year, season, episode, type, list, lock, message_queue):
            from entertainment.net import Net
            net = Net()
            
            title = self.CleanTextForSearch(title) 
            name = self.CleanTextForSearch(name)
            
            # write the code to search the source website for the page containing hosters
            # store the page url in the variable url
            #  ...
            #  ...
            # url
    
            self.GetFileHosts(url, list, lock, message_queue)
    All done

  4. #4
    Administrator
    Join Date
    Sep 2013
    Posts
    84
    Code an Indexer for iStream

    1. Follow the steps in post#2 of this thread: Setting up an XBMC Addon for iStream extension; before you continue.

    2. Create the file: myfirstindexer.py under directory: /script.icechannel.extn.tutorial/plugins/tvandmovies/

    3. Add the following imports to myfirstindexer.py
    Code:
    from entertainment.plugnplay import Plugin
    from entertainment import common
    4. Add following imports as you need them
    - if TV Indexer, Add: from entertainment.plugnplay.interfaces import TVShowIndexer
    - if Movie Indexer, Add: from entertainment.plugnplay.interfaces import MovieIndexer
    - if both TV and Movie Indexer, Add both the above imports.

    For this example we assume that the indexer is for both TV and Movies. The rest of the code in this tutorial will also follow this assumption:
    Code:
    from entertainment.plugnplay.interfaces import TVShowIndexer
     from entertainment.plugnplay.interfaces import MovieIndexer
    5. Define your indexer class. Make sure the the name of the file and the name of class is same. Since our filename is myfirstindexer.py, our class should be myfirstindexer. Also, since we are coding a Movie and TV Indexr, the code should look like as follows.
    Code:
    class myfirstindexer(MovieIndexer, TVShowIndexer):
         implements = [MovieIndexer, TVShowIndexer]
    				
         name = "MyFirstIndexer" #unique name for the addon
         display_name = "My First Indexer" #display name for the addon
         base_url = 'http://myfirstindexer.tv' #base_url of the source site

    6. Define GetSection function in the class.

    This function is the entry point for the indexer, i.e. When iStream will load this indexer, it will call this function. This would let you define the entire menu for your indexer.

    The signature and parameter details for this function are as follows.
    def GetSection(self, indexer, section, url, type, list, page='', total_pages='', sort_by='', sort_order='')
    - indexer: possible value: movies or tv_shows, defines whether to load movie or tv menu
    - section: the section-id of the indexer to load. The first call will have 'main' as section. Next calls would have whatever section-id you defined when adding the section by calling AddSection function.
    - url: the page_url of the section from the website
    - type: possible values - movies, tv_shows, tv_seasons, tv_episodes
    - list: menu items will be added to this list
    - page: used for pagination, the page to fetch
    - total_pages: used for pagination, the total pages available
    - sort_by: used for sort criteria, this is an advanced topic
    - sort_order: ascending or descending, advanced topic

    To add a section you can call AddSection function:
    def AddSection(self, list, indexer, section, title, url='', type='', hlevel=0)
    - list: section is added to this list
    - indexer: movies or tv_shows
    - section: section-id
    - title: section-title: this is displayed
    - url: url, if there is a url associated with the section
    - type: the type of the section being added: movies, tv_shows, tv_seasons, tv_episodes

    Now for an example to this function, lets say, I want to add three items to display whenever the indexer is called. It does not matter whether its for TV Shows or Movies, we want to display the following three items.

    ITEM-1. A-Z: Inside this would be #,A,B,C....Z
    ITEM-2. Genres: Inside this would be the genre available on the site
    ITEM-3. Featured: Inside this would be the items that are in featured section of the site

    Code:
    def GetSection(self, indexer, section, url, type, list, page='', total_pages='', sort_by='', sort_order=''): 
            if section == 'main':
                # ITEM-1
                self.AddSection(list, indexer, 'a_z', 'A-Z')
                
                # ITEM-2
                self.AddSection(list, indexer, 'genres', 'Genres')
            
                # ITEM-3
                #url = the complete url that lists the featured items on the site. 
                #say something like:
                #   for movies: url = http://myfirstindexer.tv/featuredmovies
                #   for tv shows: url = http://myfirstindexer.tv/featuredtvshows
                featured_url = 'http://myfirstindexer.tv/featuredmovies' if indexer == 'movies' else 'http://myfirstindexer.tv/featuredtvshows'
                type = indexer #type will be the same as indexer, as the section will either contain movies or tv_shows
                self.AddSection(list, indexer, 'featured', 'Featured', featured_url, type)
    Now lets extend this function more. We added three sections above. Since, we added sections, when user goes into those sections, iStream would call GetSection function with the section-id provided with AddSection call. Lets see how the function would grow:

    Code:
    def GetSection(self, indexer, section, url, type, list, page='', total_pages='', sort_by='', sort_order=''): 
            if section == 'main':
                ...
                ...
                ...
            elif section == 'a_z':
                self.AddSection(list, indexer, 'a', 'A', 'http://myfirstindexer.tv/letter=a')
                self.AddSection(list, indexer, 'b', 'B', 'http://myfirstindexer.tv/letter=b')
                #...
                #...
                #...
            elif section == 'genres'
                # get the genre list from the website
                # and add them using self.AddSection(...)
    Till now we were only adding sections, now lets see how to content i.e. Movies and TV Shows. The Featured section that we added earlier, when it is accessed, it definitely would bring up the content. To add content, we use the function AddContent:

    def AddContent(self, list, indexer, mode, title, id, type, url='', name='', year='', season='', episode='', img='', genre='', plot='', imdb_id='')
    - list: the list to which the content is added
    - indexer: movies or tv_shows
    - mode: mode = 'content' if type == 'tv_shows' or 'tv_episodes' else 'file_hosts'
    - title: title of the movie or tv episode
    - id: identifier for the item; for movies and tv shows: its the title, for tv season: its tv show title + the season number; for tv episode: its tv shows title + season number + episode number
    - type: type of content, possible values: movies, tv_shows, tv_seasons, tv_episodes
    - url: the url on the site, that provides details of this content item, for tv shows, orret url can help you extract season and episodes information.
    - name: name of the movie or tv show
    - year: year released or started for movie or tv show respectively
    - season: season
    - episode: episode
    - img, genre, plot, imdb_id: ignore for now

    So, with featured section and added content the GetSection function would be something like this:
    Code:
    def GetSection(self, indexer, section, url, type, list, page='', total_pages='', sort_by='', sort_order=''): 
            if section == 'main':
                ...
                ...
                ...
            elif section == 'a_z':
                self.AddSection(list, indexer, 'a', 'A', 'http://myfirstindexer.tv/letter=a')
                self.AddSection(list, indexer, 'b', 'B', 'http://myfirstindexer.tv/letter=b')
                #...
                #...
                #...
            elif section == 'genres'
                # get the genre list from the website
                # and add them using self.AddSection(...)                
            elif setion == 'featured':
                # write code to open the featured url that is passed in param 'url'
                # parse thru the page and for each item call AddContent(...)
                
                # if indexer == movies: we can directly use mode as file hosts            
                # but for tv shows, we need to use mode as content,
                #     because a tv shows has tv season and then tv episodes available as content under it
                item_mode = 'file_hosts' if indexer == 'movies' else 'content'
                
                # if indexer == movies: we can use type = movies            
                # but for tv shows, we need to pass type as tv_seasons
                #     because the underlying type of content within tv_shows is tv_seasons
                item_type = 'movies' if indexer == 'movies' else 'tv_seasons'
                
                foreach item found on the page:
                     get item_title, item_id, item_url, item_name, item_year for the item
                     self.AddContent(list, indexer, item_mode, item_title, item_id, item_type, item_url, item_name, item_year)
    If the content on featured url is in pages, and you need to support pagination, developer only needs to extract the total-pages available and call AddInfo(...) function before adding any content. And modify the code to take into account the page and total_pages values being passed with GetContent. Adding something like this
    Code:
                # for pagination             
                if page == '' or page == '0': 
                # first call set page  == '1'
                    page = '1'
                    # extract total pages from the url into varial totalpages
                    total_pages = ...
                
                self.AddInfo(list, indexer, section, url, type, page, total_pages)


    7. Add GetContent function

    Only add for TV Show Indexer. If you remember correctly, we used AddContent function earlier and passed 'content' as mode value when indexer was tv_shows. Now, when user goes into a TV Show or a TV Season, iStream calls GetContent function of the Indexer.

    def GetContent(self, indexer, url, title, name, year, season, episode, type, list)
    - indexer: will always be tv_shows
    - url: url of the tv show or tv season on the website, that can be used to extract season or episode infomration
    - title: tile of the tv show
    - name: name of the tv show
    - year: year first episode aired
    - season: season number
    - episode: episode number
    - type: type of the content, possible values: tv_seasons, tv_episodes
    - list: list to which content is added.
    Code:
        def GetContent(self, indexer, url, title, name, year, season, episode, type, list):      
            
            if type == 'tv_seasons':        
                # Get the seasons from the url for the tv show in title, name and year
                # for each season call AddContent function
                #   with mode='content' and type='tv_episodes' and season=season etc...
                    
            elif type == 'tv_episodes':
                # Get the episodes from the url for the season for tv show name and year
                # for each episode call AddContent function
                #   with mode='file_hosts' and type='tv_episodes' and season=season and episode=episode etc...


    The entire code would look something like this:

    Code:
    # file: myfirstindexer.py
    # location: /script.icechannel.extn.tutorial/plugins/tvandmovies/
    
    from entertainment.plugnplay import Plugin
    from entertainment import common
    
    from entertainment.plugnplay.interfaces import TVShowIndexer
    from entertainment.plugnplay.interfaces import MovieIndexer
    
    class myfirstindexer(MovieIndexer, TVShowIndexer):
        implements = [MovieIndexer, TVShowIndexer]
    	
        #unique name of the source
        name = "MyFirstIndexer"
        
        #display name of the source
        display_name = "My First Indexer"
        
        #base url of the source website
        base_url = 'http://myfirstindexer.tv'
        
        def GetSection(self, indexer, section, url, type, list, page='', total_pages='', sort_by='', sort_order=''): 
            if section == 'main':
                # ITEM-1
                self.AddSection(list, indexer, 'a_z', 'A-Z')
                
                # ITEM-2
                self.AddSection(list, indexer, 'genres', 'Genres')
            
                # ITEM-3
                #url = the complete url that lists the featured items on the site. 
                #say something like:
                #   for movies: url = http://myfirstindexer.tv/featuredmovies
                #   for tv shows: url = http://myfirstindexer.tv/featuredtvshows
                featured_url = 'http://myfirstindexer.tv/featuredmovies' if indexer == 'movies' else 'http://myfirstindexer.tv/featuredtvshows'
                type = indexer #type will be the same as indexer, as the section will either contain movies or tv_shows
                self.AddSection(list, indexer, 'featured', 'Featured', featured_url, type)
            elif section == 'a_z':
                self.AddSection(list, indexer, 'a', 'A', 'http://myfirstindexer.tv/letter=a')
                self.AddSection(list, indexer, 'b', 'B', 'http://myfirstindexer.tv/letter=b')
                #...
                #...
                #...
            elif section == 'genres'
                # get the genre list from the website
                # and add them using self.AddSection(...)
            elif setion == 'featured':
                # write code to open the featured url that is passed in param 'url'
                
                # for pagination             
                if page == '' or page == '0': 
                # first call set page  == '1'
                    page = '1'
                    # extract total pages from the url into varial totalpages
                    total_pages = ...
                
                self.AddInfo(list, indexer, section, url, type, page, total_pages)
                
                
                # parse thru the page and for each item call AddContent(...)
                
                # if indexer == movies: we can directly use mode as file hosts            
                # but for tv shows, we need to use mode as content,
                #     because a tv shows has tv season and then tv episodes available as content under it
                item_mode = 'file_hosts' if indexer == 'movies' else 'content'
                
                # if indexer == movies: we can use type = movies            
                # but for tv shows, we need to pass type as tv_seasons
                #     because the underlying type of content within tv_shows is tv_seasons
                item_type = 'movies' if indexer == 'movies' else 'tv_seasons'
                
                foreach item found on the page:
                    get item_title, item_id, item_url, item_name, item_year
                    self.AddContent(list, indexer, item_mode, item_title, item_id, item_type, item_url, item_name, item_year)
                
        def GetContent(self, indexer, url, title, name, year, season, episode, type, list):      
            
            if type == 'tv_seasons':        
                # Get the seasons from the url for the tv show in title, name and year
                # for each season call AddContent function
                #   with mode='content' and type='tv_episodes' and season=season etc...
                    
            elif type == 'tv_episodes':
                # Get the episodes from the url for the season for tv show name and year
                # for each episode call AddContent function
                #   with mode='file_hosts' and type='tv_episodes' and season=season and episode=episode etc...

  5. #5
    Administrator
    Join Date
    Sep 2013
    Posts
    84
    iStream Helper Functions

    iStream includes many helper functions that devs can use within their own sources and indexers.

    Details Coming Soon

  6. #6
    Administrator
    Join Date
    Sep 2013
    Posts
    84
    TO ALL DEVS: Please follow the guide, write and share your sources and indexers in the sub forum: iStream Extensions

    Help us improve the guide along the way.


    NOW EVERYONE CAN CONTRIBUTE TO ISTREAM

  7. #7
    That's why he did it, LOL

  8. #8
    user_one
    Guest
    I'm working on http://www.nzbmovieseeker.com/ and http://www.nzbtvseeker.com/ as a indexer. Will take me a bit to finish but this is what im working on.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •