Kodi Community Forum
Release Retrospect v5.5.x Video Add-On - Printable Version

+- Kodi Community Forum (https://forum.kodi.tv)
+-- Forum: Support (https://forum.kodi.tv/forumdisplay.php?fid=33)
+--- Forum: Add-on Support (https://forum.kodi.tv/forumdisplay.php?fid=27)
+---- Forum: Video Add-ons (https://forum.kodi.tv/forumdisplay.php?fid=154)
+---- Thread: Release Retrospect v5.5.x Video Add-On (/showthread.php?tid=25522)



- Basje - 2008-11-06

freddeg Wrote:Hi I'm tying to play aktuelt but i cant get it to work.

Log:
Code:
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - Fetching info for 'Måndag 3 november'. Setting:
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - | Description: Start
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - | Nyheter
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt 21
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - | Måndag 3 november
20081106 16:38:20 - DEBUG    - guicontroller.py - 127 - + Image: /home/fredde/.xbmc/scripts/test/channels/svt/svtimage.png
20081106 16:38:20 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081106 16:38:20 - DEBUG    - chn_svt.py       - 216 - Parsing ASX
20081106 16:38:20 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx (already 1 threads)
20081106 16:38:21 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081106 16:38:21 - INFO     - uriopener.py     - 422 - FileSize is known (fileSize=225)
20081106 16:38:21 - INFO     - uriopener.py     - 194 - Url http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx was opened successfully
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - On Click error showing episodes
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - | Traceback (most recent call last):
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |   File "/home/fredde/.xbmc/scripts/test/resources/libs/chn_class.py", line 365, in onClick
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |     self.PlayVideoItem(item)
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |   File "/home/fredde/.xbmc/scripts/test/channels/svt/chn_svt.py", line 206, in PlayVideoItem
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |     item.mediaurl = self.ReplaceMediaUrl(item.mediaurl)
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |   File "/home/fredde/.xbmc/scripts/test/channels/svt/chn_svt.py", line 220, in ReplaceMediaUrl
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - |     mediaurl = results[0]['href']
20081106 16:38:21 - CRITICAL - chn_class.py     - 409 - | TypeError: string indices must be integers
20081106 16:38:21 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=11 and id=7) detected (ThrdID=-1491080304)

Could you try opening the chn_svt.py in notepad and remove the ['href'] from line 220. Please let me know if it works.


svt - freddeg - 2008-11-07

No that didn't help. But I'm think its about xbmc now. I'm on linux and maybe the player for linux version can't handle svt's stream right. When i try to play some streams then it's just says it's buffering and some its aborting.
log for aborting:
Code:
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - Fetching info for 'Måndag 3 november'. Setting:
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Description: Start
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Nyheter
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt 21
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Måndag 3 november
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - + Image: /home/fredde/.xbmc/scripts/XOT-Uzg.v3/channels/svt/svtimage.png
20081107 12:10:20 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081107 12:10:20 - DEBUG    - chn_svt.py       - 221 - Parsing ASX
20081107 12:10:20 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx (already 1 threads)
20081107 12:10:20 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081107 12:10:20 - INFO     - uriopener.py     - 422 - FileSize is known (fileSize=225)
20081107 12:10:20 - INFO     - uriopener.py     - 194 - Url http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx was opened successfully
20081107 12:10:20 - INFO     - chn_svt.py       - 208 - Starting Video Playback of mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/081103aktuellt21.wmv using the defaultplayer
20081107 12:10:20 - INFO     - chn_class.py     - 922 - Starting Video Playback using the defaultplayer
20081107 12:10:20 - INFO     - chn_class.py     - 930 - Going to playback a single item mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/081103aktuellt21.wmv
20081107 12:10:20 - INFO     - chn_class.py     - 940 - Playing using default player
20081107 12:10:24 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=11 and id=7) detected (ThrdID=-1490035824)

log for buffering:
Code:
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - Fetching info for 'Måndag 3 november (Textad version)'. Setting:
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Description: Start
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Nyheter
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Aktuellt
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Aktuellt 21
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Måndag 3 november (Textad version)
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - + Image: /home/fredde/.xbmc/scripts/XOT-Uzg.v3/channels/svt/svtimage.png
20081107 12:21:40 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081107 12:21:40 - DEBUG    - chn_svt.py       - 221 - Parsing ASX
20081107 12:21:40 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://www.svt.se/content/1/c8/01/10/89/61/textnyheter1692100mandagtext.asx (already 1 threads)
20081107 12:21:40 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081107 12:21:40 - INFO     - uriopener.py     - 422 - FileSize is known (fileSize=237)
20081107 12:21:40 - INFO     - uriopener.py     - 194 - Url http://www.svt.se/content/1/c8/01/10/89/61/textnyheter1692100mandagtext.asx was opened successfully
20081107 12:21:40 - INFO     - chn_svt.py       - 208 - Starting Video Playback of mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/textnyheter1692100mandagtext.wmv using the defaultplayer
20081107 12:21:40 - INFO     - chn_class.py     - 922 - Starting Video Playback using the defaultplayer
20081107 12:21:40 - INFO     - chn_class.py     - 930 - Going to playback a single item mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/textnyheter1692100mandagtext.wmv
20081107 12:21:40 - INFO     - chn_class.py     - 940 - Playing using default player
20081107 12:21:44 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=11 and id=7) detected (ThrdID=-1490035824)



- ^Mask^ - 2008-11-09

Hi Basje,

Based on your recommendation, I started work on chn_net5.py and been screwing around with it. Indeed, you are right: I have no idea what's happening and therefore the results just dont make sense.

Quote:- UpdateVideoItem is called when the Complete property of a videoItem is not set. It can for example determine the mediaUrl or download a thumb.

So to be short. A basic channel only needs:
- InitialiseVariables (with correct parameters, regexes and a unique GUID (so not a copied one).
- CreateEpisodeItem
- CreateVideoItem
- CreateFolderItem
- UpdateVideoItem

Ok, so I get the part on what is needed: InitialiseVariables, CreateEpisodeItem and CreateVideoItem. CreateFolderItem is only required if you need to create a folder (for example of a set of programs, or maybe even splitting it up in "Seasons"). UpdateVideoItem is only used in case you don't have all the information (item.complete = False) (for example: the episode link only shows a href to part of the fully qualified url: /media/files/whatever.asf instead of http://www.myurl.com/media/files/whatever.asf or a missing thumb, whatever).

Where you still lose me is on the rest and I really apologize for taking up more of your precious time:

Quote:XOT uses a Programs - Files/Folders - Files/Folders - ..............structure.

Ok, I think I get that: I imagine you to use the word Program as a synonym for "TV-Shows", right? Like an online TV channel hosts multiple different TV Shows, and therefore a TV Show (or Program) could have multiple files under it, hence your statement Programs - Files.

Next, Folders contain Files (got it: Seasons could have different Episodes, or they could create different Categories like "Funny" with a long list of videos to view).

Finally: Folders can again contain other things like new folders or new programs.

Next part:
Quote:- ParseMainlists gives you a list of programs and does not need to be used, because you can define stuff in the CreateEpisodeItem method. It uses the results from the regex which are in the "resultSet" parameter that is passed on to the method.

Ok, so ParseMainlists module is only needed in case you want to parse the main page for programs or in case you want to just define your own folder with different feed formats. In my case, what I can do is define different folders there for the different file formats: H264, iPOD, DivX and MPEG-4. Each of these folders has a different XML feed attached that can be parsed.

The part that confuses me is what comes next:

CreateEpisodeItem
CreateVideoItem
CreateFolderItem

Can you share with me what each of these modules does, maybe according to a simple example? So, ParseMainList takes the mainURL and uses self.episodeItemRegex to create a list of items using CreateEpisodeItem. CreateVideoItem and CreateFolderItem are the ones that actually create entries on the list, is it?

Let me share what I have now and hope you can help me figure things out:


- ^Mask^ - 2008-11-09

Code:
#===============================================================================
# Import the default modules
#===============================================================================
import xbmc, xbmcgui
import re, sys, os
import urlparse
#===============================================================================
# Make global object available
#===============================================================================
import common
import config
import controls
import contextmenu
import chn_class

logFile = sys.modules['__main__'].globalLogFile
uriHandler = sys.modules['__main__'].globalUriHandler

#===============================================================================
# register the channels
#===============================================================================
if (sys.modules.has_key('progwindow')):
    register = sys.modules['progwindow']
elif (sys.modules.has_key('plugin')):
    register = sys.modules['plugin']
#register.channelButtonRegister.append(108)
register.channelRegister.append('chn_commandn.Channel("uzg-channelwindow.xml", config.rootDir, config.skinFolder, channelCode="commandn")')

#===============================================================================
# main Channel Class
#===============================================================================
class Channel(chn_class.Channel):
    """
    main class from which all channels inherit
    """
    
    #===============================================================================
    def InitialiseVariables(self):
        """
        Used for the initialisation of user defined parameters. All should be
        present, but can be adjusted
        """
        # call base function first to ensure all variables are there
        chn_class.Channel.InitialiseVariables(self)
        
        self.guid = "B374230E-42F3-11DD-984E-E2F555D89523"
        self.icon = "commandnicon.png"
        self.iconLarge = "commandnlarge.png"
        self.noImage = "commandnimage.png"
        self.channelName = "Command-N"
        self.maxXotVersion = "3.2.0"
        self.channelDescription = "Command-N Episodes"
        self.sortOrder = 6
        self.moduleName = "chn_commandn.py"
        self.mainListUri = "http://feeds.feedburner.com/command-n/h264"
#        self.baseUrl = "http://www.net5.nl"
#        self.onUpDownUpdateEnabled = True
        
        self.contextMenuItems = []
#        self.contextMenuItems.append(contextmenu.ContextMenuItem("Update Item", "CtMnUpdateItem", itemTypes="video", completeStatus=None))            
#        self.contextMenuItems.append(contextmenu.ContextMenuItem("Download Item", "CtMnDownloadItem", itemTypes="video", completeStatus=True))
        self.contextMenuItems.append(contextmenu.ContextMenuItem("Play using Mplayer", "CtMnPlayMplayer", itemTypes="video", completeStatus=True))
        self.contextMenuItems.append(contextmenu.ContextMenuItem("Play using DVDPlayer", "CtMnPlayDVDPlayer", itemTypes="video", completeStatus=True))
                
        self.requiresLogon = False
        
#        self.episodeItemRegex = '<div class="thumb">\W+<a[^>]+href="(/[^"]+)"[^>]*>\W+<img[^>]+alt="([^"]+)"/>' # used for the ParseMainList
#        self.episodeItemRegex = '<item>.*<title>([^<]+).*<link>([^<]+).*</item>'   # used for the ParseMainList
        self.videoItemRegex = '<item>\W+<title>([^<]+)</title>\W+<link>([^<]+)</link>[^]+<pubDate>([^]+)</pubDate>[^]+<itunes:summary>([^]+)</itunes:summary>[^]+</item>'   # used for the CreateVideoItem
#        self.pageNavigationRegex = '<a href="([^"]+)(\d+)"><span>\d+</span></a>' #self.pageNavigationIndicationRegex
#        self.pageNavigationRegexIndex = 1
                
        # decrepated. Using url based on ID now
        #self.mediaUrlRegex = '<param name="src" value="([^"]+)" />'    # used for the UpdateVideoItem
        
        return True
      
    #==============================================================================
    # ContextMenu functions
    #==============================================================================
#    def CtMnUpdateItem(self, selectedIndex):
#        logFile.debug('Updating item (Called from ContextMenu)')
#        self.onUpDown(ignoreDisabled = True)
#    
#    def CtMnDownloadItem(self, selectedIndex):
#        item = self.listItems[selectedIndex]
#        self.listItems[selectedIndex] = self.DownloadEpisode(item)

    def CtMnPlayMplayer(self, selectedIndex):
        item = self.listItems[selectedIndex]
        self.PlayVideoItem(item, "mplayer")
    
    def CtMnPlayDVDPlayer(self, selectedIndex):
        item = self.listItems[selectedIndex]
        self.PlayVideoItem(item,"dvdplayer")    

    #==============================================================================
    def ParseMainList(self):

        items = []
        
        item = common.clistItem("Command-N iPod Videos", "http://feeds.feedburner.com/commandN_pod")
        item.icon = self.folderIcon
        items.append(item)
    
        item = common.clistItem("Command-N XViD Videos", "http://feeds.feedburner.com/command-n/xvid")
        item.icon = self.folderIcon
        items.append(item)

        item = common.clistItem("Command-N MPEG-4 Videos", "http://feeds.feedburner.com/command-n/mpeg4")
        item.icon = self.folderIcon
        items.append(item)

        item = common.clistItem("Command-N H-264 Videos", "http://feeds.feedburner.com/command-n/h264")
        item.icon = self.folderIcon
        items.append(item)

        return items

    #==============================================================================
#    def CreateEpisodeItem(self, resultSet):
#        """
#        Accepts an arraylist of results. It returns an item.
#        """
#        logFile.debug('starting CreateEpisodeItem for %s', self.channelName)
#        
#        # dummy class
#        item = common.clistItem(resultSet[1], resultSet[0])
#        item.icon = self.icon
#        item.complete = True
#        return item
    
    #=============================================================================
    def CreateVideoItem(self, resultSet):
        """
        Accepts an arraylist of results. It returns an item.
        """
        logFile.debug('starting CreateVideoItem for %s', self.channelName)
        logFile.debug(resultSet)
        
        item = common.clistItem(resultSet[0], resultSet[1])
        
        item.thumb = self.noImage
        item.icon = self.icon
        item.type = 'video'

        item.mediaurl = resultSet[1]
        item.date = resultSet[2]
        item.description = resultSet[3]
        logFile.debug('Title: ', self.title, self.channelName)
        logFile.debug('URL: ', self.url, self.channelName)
        logFile.debug('Date: ', self.date, self.channelName)
        logFile.debug('MediaURL: ', self.mediaurl, self.channelName)
        logFile.debug('Description: ', self.description, self.channelName)

        item.complete = True
        
        return item
    
    #=============================================================================
#    def UpdateVideoItem(self, item):
#        """
#        Accepts an item. It returns an updated item. Usually retrieves the MediaURL
#        and the Thumb! It should return a completed item.
#        """
#        logFile.info('starting UpdateVideoItem for %s (%s)', item.name, self.channelName)
#        
#        #item.thumb = self.CacheThumb(item.thumbUrl)        
#        
#        # now the mediaurl is derived
#        # http://www.garnierstreamingmedia.com/asx/openclip.asp?file=/sbs6/net5/juliastango_S02/juliastango_S02E07.wmv
#        #                                             http://asx.sbsnet.nl/net5/juliastango_S02/juliastango_S02E07.wmv
#        
#        data = uriHandler.Open(item.url, pb=False)
#        urls = common.DoRegexFindAll('<a class="wmv-player-holder" href="(http://asx.sbsnet.nl/net5/)([^"]+)"></a>', data)
#        for url in urls:
#            item.mediaurl = "http://www.garnierstreamingmedia.com/asx/openclip.asp?file=/sbs6/net5/%s" % (url[1])
#        
#        if item.mediaurl != "":
#            logFile.debug("Media url was found: %s", item.mediaurl)
#            item.complete = True
#        else:
#            logFile.debug("Media url was not found.")
#        return item



- ^Mask^ - 2008-11-09

This results into:

Code:
20081109 14:28:18 - DEBUG    - progwindow.py    - 232 - onClick ControlID=51
20081109 14:28:18 - DEBUG    - progwindow.py    - 118 - Resetting self.click
20081109 14:28:18 - DEBUG    - progwindow.py    - 159 - Progwindow :: Performing a SelectItem
20081109 14:28:18 - DEBUG    - progwindow.py    - 181 - onSelect on ControlID=51
20081109 14:28:19 - DEBUG    - progwindow.py    - 363 - Hiding Channels
20081109 14:28:19 - DEBUG    - progwindow.py    - 247 - onFocus :: Control 60 has focus now
20081109 14:28:20 - DEBUG    - progwindow.py    - 118 - Resetting self.click
20081109 14:28:20 - CRITICAL - progwindow.py    - 171 - OnAction::unknow action (id=4). Do not know what to do
20081109 14:28:20 - DEBUG    - progwindow.py    - 118 - Resetting self.click
20081109 14:28:20 - CRITICAL - progwindow.py    - 171 - OnAction::unknow action (id=4). Do not know what to do
20081109 14:28:20 - DEBUG    - progwindow.py    - 118 - Resetting self.click
20081109 14:28:20 - CRITICAL - progwindow.py    - 171 - OnAction::unknow action (id=4). Do not know what to do
20081109 14:28:21 - DEBUG    - progwindow.py    - 232 - onClick ControlID=60
20081109 14:28:21 - DEBUG    - progwindow.py    - 118 - Resetting self.click
20081109 14:28:21 - DEBUG    - progwindow.py    - 159 - Progwindow :: Performing a SelectItem
20081109 14:28:21 - DEBUG    - progwindow.py    - 181 - onSelect on ControlID=60
20081109 14:28:21 - INFO     - progwindow.py    - 208 - opening episode list GUI with uri=http://feeds.feedburner.com/command-n/h264
20081109 14:28:21 - INFO     - chn_class.py     - 152 - onInit(): Window Initalized for chn_commandn.py
20081109 14:28:21 - DEBUG    - chn_class.py     - 154 - Initializing Command-N Gui for the first time
20081109 14:28:21 - DEBUG    - chn_class.py     - 167 - Clearing Folder History
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - Fetching info for ''. Setting:
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - | Description: Please wait while loading data
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - + Image: Q:\scripts\XOT-Uzg.v3\channels\commandn\commandnimage.png
20081109 14:28:21 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081109 14:28:21 - DEBUG    - chn_class.py     - 181 - LogonCheck
20081109 14:28:21 - INFO     - chn_class.py     - 876 - No login required of Command-N
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - Fetching info for ''. Setting:
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - | Description: Please wait while loading data
20081109 14:28:21 - DEBUG    - guicontroller.py - 127 - + Image: Q:\scripts\XOT-Uzg.v3\channels\commandn\commandnimage.png
20081109 14:28:21 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081109 14:28:21 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://feeds.feedburner.com/command-n/h264 (already 1 threads)
20081109 14:28:22 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081109 14:28:22 - INFO     - uriopener.py     - 425 - FileSize is unknown
20081109 14:28:26 - INFO     - uriopener.py     - 194 - Url http://feeds.feedburner.com/command-n/h264 was opened successfully
20081109 14:28:26 - INFO     - chn_class.py     - 647 - Performing Pre-Processing
20081109 14:28:26 - DEBUG    - chn_class.py     - 649 - Pre-Processing finished
20081109 14:28:26 - CRITICAL - common.py        - 102 - error regexing
20081109 14:28:26 - CRITICAL - common.py        - 102 - | Traceback (most recent call last):
20081109 14:28:26 - CRITICAL - common.py        - 102 - |   File "Q:\scripts\XOT-Uzg.v3\resources\libs\common.py", line 99, in DoRegexFindAll
20081109 14:28:26 - CRITICAL - common.py        - 102 - |     result = re.compile(regex, re.DOTALL + re.IGNORECASE)
20081109 14:28:26 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 180, in compile
20081109 14:28:26 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 227, in _compile
20081109 14:28:26 - CRITICAL - common.py        - 102 - | error: unbalanced parenthesis
20081109 14:28:27 - DEBUG    - guicontroller.py - 46  - DisplayPageNavigation starting
20081109 14:28:27 - DEBUG    - guicontroller.py - 69  - DisplayFolderList needs to display 0 items.
20081109 14:28:27 - DEBUG    - guicontroller.py - 69  - + Focussed is on item 0
20081109 14:28:27 - DEBUG    - guicontroller.py - 73  - Adding Dummy Item
20081109 14:28:27 - INFO     - guicontroller.py - 119 - All items where shown. Now fetching focussed item info for item number 0
20081109 14:28:27 - DEBUG    - guicontroller.py - 127 - Fetching info for 'No Files'. Setting:
20081109 14:28:27 - DEBUG    - guicontroller.py - 127 - | Description:
20081109 14:28:27 - DEBUG    - guicontroller.py - 127 - + Image: Q:\scripts\XOT-Uzg.v3\channels\commandn\commandnimage.png
20081109 14:28:27 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081109 14:28:27 - DEBUG    - chn_class.py     - 209 - Command-N Gui has been initialised for the first time
20081109 14:28:29 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=275 and id=10) detected (ThrdID=592)
20081109 14:28:29 - DEBUG    - chn_class.py     - 260 - Removing items from historystack
20081109 14:28:30 - DEBUG    - progwindow.py    - 247 - onFocus :: Control 60 has focus now
20081109 14:28:31 - DEBUG    - progwindow.py    - 118 - Resetting self.click



- Basje - 2008-11-09

freddeg Wrote:No that didn't help. But I'm think its about xbmc now. I'm on linux and maybe the player for linux version can't handle svt's stream right. When i try to play some streams then it's just says it's buffering and some its aborting.
log for aborting:
Code:
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - Fetching info for 'Måndag 3 november'. Setting:
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Description: Start
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Nyheter
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Aktuellt 21
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - | Måndag 3 november
20081107 12:10:20 - DEBUG    - guicontroller.py - 127 - + Image: /home/fredde/.xbmc/scripts/XOT-Uzg.v3/channels/svt/svtimage.png
20081107 12:10:20 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081107 12:10:20 - DEBUG    - chn_svt.py       - 221 - Parsing ASX
20081107 12:10:20 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx (already 1 threads)
20081107 12:10:20 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081107 12:10:20 - INFO     - uriopener.py     - 422 - FileSize is known (fileSize=225)
20081107 12:10:20 - INFO     - uriopener.py     - 194 - Url http://www.svt.se/content/1/c6/32/93/31/081103aktuellt21.asx was opened successfully
20081107 12:10:20 - INFO     - chn_svt.py       - 208 - Starting Video Playback of mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/081103aktuellt21.wmv using the defaultplayer
20081107 12:10:20 - INFO     - chn_class.py     - 922 - Starting Video Playback using the defaultplayer
20081107 12:10:20 - INFO     - chn_class.py     - 930 - Going to playback a single item mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/081103aktuellt21.wmv
20081107 12:10:20 - INFO     - chn_class.py     - 940 - Playing using default player
20081107 12:10:24 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=11 and id=7) detected (ThrdID=-1490035824)

log for buffering:
Code:
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - Fetching info for 'Måndag 3 november (Textad version)'. Setting:
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Description: Start
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Nyheter
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Aktuellt
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Aktuellt 21
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - | Måndag 3 november (Textad version)
20081107 12:21:40 - DEBUG    - guicontroller.py - 127 - + Image: /home/fredde/.xbmc/scripts/XOT-Uzg.v3/channels/svt/svtimage.png
20081107 12:21:40 - DEBUG    - guicontroller.py - 146 - Showing rating: None
20081107 12:21:40 - DEBUG    - chn_svt.py       - 221 - Parsing ASX
20081107 12:21:40 - INFO     - uriopener.py     - 148 - Opening requested uri Async: http://www.svt.se/content/1/c8/01/10/89/61/textnyheter1692100mandagtext.asx (already 1 threads)
20081107 12:21:40 - INFO     - uriopener.py     - 417 - Determining which Progessbar to use....
20081107 12:21:40 - INFO     - uriopener.py     - 422 - FileSize is known (fileSize=237)
20081107 12:21:40 - INFO     - uriopener.py     - 194 - Url http://www.svt.se/content/1/c8/01/10/89/61/textnyheter1692100mandagtext.asx was opened successfully
20081107 12:21:40 - INFO     - chn_svt.py       - 208 - Starting Video Playback of mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/textnyheter1692100mandagtext.wmv using the defaultplayer
20081107 12:21:40 - INFO     - chn_class.py     - 922 - Starting Video Playback using the defaultplayer
20081107 12:21:40 - INFO     - chn_class.py     - 930 - Going to playback a single item mms://wm0.c90805.cdn.qbrick.com/90805/kluster/20081103/textnyheter1692100mandagtext.wmv
20081107 12:21:40 - INFO     - chn_class.py     - 940 - Playing using default player
20081107 12:21:44 - DEBUG    - chn_class.py     - 241 - onAction (with buttonid=11 and id=7) detected (ThrdID=-1490035824)

Your problem is indeed an XBMC problem. XOT now determines the correct media url. I will fix it in the current channel and post an update.


- Basje - 2008-11-09

^Mask^ Wrote:Ok, so I get the part on what is needed: InitialiseVariables, CreateEpisodeItem and CreateVideoItem. CreateFolderItem is only required if you need to create a folder (for example of a set of programs, or maybe even splitting it up in "Seasons"). UpdateVideoItem is only used in case you don't have all the information (item.complete = False) (for example: the episode link only shows a href to part of the fully qualified url: /media/files/whatever.asf instead of http://www.myurl.com/media/files/whatever.asf or a missing thumb, whatever).
Yep, this is completely true.

^Mask^ Wrote:Ok, I think I get that: I imagine you to use the word Program as a synonym for "TV-Shows", right? Like an online TV channel hosts multiple different TV Shows, and therefore a TV Show (or Program) could have multiple files under it, hence your statement Programs - Files.

Next, Folders contain Files (got it: Seasons could have different Episodes, or they could create different Categories like "Funny" with a long list of videos to view).
This is exactly what I meant.

^Mask^ Wrote:Finally: Folders can again contain other things like new folders or new programs.
Nope, folders can only contain other folders and video files.

^Mask^ Wrote:Ok, so ParseMainlists module is only needed in case you want to parse the main page for programs or in case you want to just define your own folder with different feed formats. In my case, what I can do is define different folders there for the different file formats: H264, iPOD, DivX and MPEG-4. Each of these folders has a different XML feed attached that can be parsed.
You don't have to define the ParseMainlists. If you don't then the default will be used (the one in chn_class.py). If you do create one, you will have to write your own code to generate items.

^Mask^ Wrote:The part that confuses me is what comes next:

CreateEpisodeItem
CreateVideoItem
CreateFolderItem

Can you share with me what each of these modules does, maybe according to a simple example? So, ParseMainList takes the mainURL and uses self.episodeItemRegex to create a list of items using CreateEpisodeItem. CreateVideoItem and CreateFolderItem are the ones that actually create entries on the list, is it?
You are almost right:

- ParseMainlist (called from chn_class.py) uses CreateEpisodeItem and the self.episodeItemRegex to create mainlist items (the naming EpisodeItem is a bit wrong/strange).
- ProcessFolderList (called from chn_class.py) uses CreateVideoItem and CreatefolderItem combined with self.folderItemRegex and self.videoItemRegex. It uses the regexes to determine what items are present on a page/url. Then for each of the results from the self.videoItemRegex it calls CreateVideoItem and passes on the results from the regex as the parameter resultSet. And for each of the results from the self.folderItemRegex it calls CreateFolderItem and passes on the results from the regex as the parameter resultSet.

So it is important that your Regexes have groups that define the name of the item and the url of the item. Let's say that the regex has 2 groups: first one gives the name and the second one the url. Then in the Create(Video/Folder)Item methode, you can use those groups like this: name = resultSet[0] and url = resultSet[1].

So what I can see from your code, it seems to be OK. But, I from the log I see that your regexes are not OK. Check if all the ( and ) are balanced.


- ^Mask^ - 2008-11-09

Hi Basje,

Thanks again for your patient explanation! I'm in urgent need of therapy I think, because I just can't seem to figure out where I'm going wrong. Let me illustrate based on a simple example:

XML Code to parse
Code:
<item>
      <title>commandN Episode 155</title>
      <link>http://www.podtrac.com/pts/redirect.mov/traffic.libsyn.com/commandnpro/commandN_155_H264.mov</link>
      <description>This week, why gamers aren't loners, the top 5 iPhone apps and how to get your phone back.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/command-n/h264?a=1p4iM"&gt;&lt;img src="http://feeds.feedburner.com/~f/command-n/h264?i=1p4iM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/command-n/h264?a=SFF2m"&gt;&lt;img src="http://feeds.feedburner.com/~f/command-n/h264?i=SFF2m" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/command-n/h264?a=BTCwM"&gt;&lt;img src="http://feeds.feedburner.com/~f/command-n/h264?i=BTCwM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;

&lt;/div&gt;</description>
      <pubDate>Fri, 31 Oct 2008 13:49:10 -0400</pubDate>
      <guid isPermaLink="false">commandn-episode-155</guid>
      <itunes:author>commandN</itunes:author>
      <itunes:explicit>no</itunes:explicit>
      <itunes:duration>11:17</itunes:duration>

    <author>[email protected] (commandN)</author><enclosure url="http://www.podtrac.com/pts/redirect.mov/traffic.libsyn.com/commandnpro/commandN_155_H264.mov" length="73327224" type="video/quicktime" /><media:content url="http://www.podtrac.com/pts/redirect.mov/traffic.libsyn.com/commandnpro/commandN_155_H264.mov" fileSize="73327224" type="video/quicktime" /><itunes:subtitle>This week, why gamers aren't loners, the top 5 iPhone apps and how to get your phone back.</itunes:subtitle><itunes:summary>This week, why gamers aren't loners, the top 5 iPhone apps and how to get your phone back.</itunes:summary><itunes:keywords>video,commandN,command,N,command,Amber,MacArthur,Jeff,MacArthur,Mike,Lazazzera,Brian,McKechnie,iPod,Apple,Mac,computers,tech,TV,techTV,television,technology,news,Podcast,commandn,Rocketboom,TWIT,Leo,Laporte,girls,hot,Web,vidcast</itunes:keywords></item>

CreateVideoItem
Code:
item = common.clistItem(resultSet[0], resultSet[1])
        item.type = 'video'

        item.complete = True

        return item

Attempted RegEx's:
Code:
<item>\W+?<title>([^]*)</title>\W+<link>([^]*)</link>[^]*</item>

or

<item>[^<]*<title>([^<]*)</title>[^<]*<media:content url="([^"]*)[^<]*</item>

or

<item>\W+?<title>([^<]+?)</title>\W+?<link>([^<]+?)</link>[^]+?<pubDate>([^]+?)</pubDate>[^]+?summary>([^<]+?)<[^<]+?>[^]+?</item>

or even:

<item>([^<]+?)</item>

I've tried multiple different approaches, but each of them I get either "error: unbalanced parenthesis" or "error: unexpected end of regular expression".

I've tested all the above reg-exes using the following URL, which all give me the correct groups with dotall and ignorecase switched on. Is XBMC/XOT using a different regex format?

http://www.gskinner.com/RegExr/

Could you have a look and see where I'm screwing up? I'm almost certain it's something teenieweenie small, but can't figure out where its going wrong (I think by now I'm responsible for starting up your script about 1000 times in the past 2 weeks lol).


- Basje - 2008-11-09

^Mask^ Wrote:Hi Basje,

Thanks again for your patient explanation! I'm in urgent need of therapy I think, because I just can't seem to figure out where I'm going wrong. Let me illustrate based on a simple example:

.....
I've tried multiple different approaches, but each of them I get either "error: unbalanced parenthesis" or "error: unexpected end of regular expression".

I've tested all the above reg-exes using the following URL, which all give me the correct groups with dotall and ignorecase switched on. Is XBMC/XOT using a different regex format?

http://www.gskinner.com/RegExr/

Could you have a look and see where I'm screwing up? I'm almost certain it's something teenieweenie small, but can't figure out where its going wrong (I think by now I'm responsible for starting up your script about 1000 times in the past 2 weeks lol).
Could you post your channel on pastebin.ca, so I have the complete overview of it?


- ^Mask^ - 2008-11-10

Hi Basje,

Actually, the code is no different from the one a few posts back. Only thing I have been playing around with is the regex and some of the values captured and stored (ie: comment out things like item.description =, to avoid it complaining about empty regex values).

Code:
#===============================================================================
# Import the default modules
#===============================================================================
import xbmc, xbmcgui
import re, sys, os
import urlparse
#===============================================================================
# Make global object available
#===============================================================================
import common
import config
import controls
import contextmenu
import chn_class

logFile = sys.modules['__main__'].globalLogFile
uriHandler = sys.modules['__main__'].globalUriHandler

#===============================================================================
# register the channels
#===============================================================================
if (sys.modules.has_key('progwindow')):
    register = sys.modules['progwindow']
elif (sys.modules.has_key('plugin')):
    register = sys.modules['plugin']
#register.channelButtonRegister.append(108)
register.channelRegister.append('chn_commandn.Channel("uzg-channelwindow.xml", config.rootDir, config.skinFolder, channelCode="commandn")')

#===============================================================================
# main Channel Class
#===============================================================================
class Channel(chn_class.Channel):
    """
    main class from which all channels inherit
    """
    
    #===============================================================================
    def InitialiseVariables(self):
        """
        Used for the initialisation of user defined parameters. All should be
        present, but can be adjusted
        """
        # call base function first to ensure all variables are there
        chn_class.Channel.InitialiseVariables(self)
        
        self.guid = "B374230E-42F3-11DD-984E-E2F555D89523"
        self.icon = "commandnicon.png"
        self.iconLarge = "commandnlarge.png"
        self.noImage = "commandnimage.png"
        self.channelName = "Command-N"
        self.maxXotVersion = "3.2.0"
        self.channelDescription = "Command-N Episodes"
        self.sortOrder = 6
        self.moduleName = "chn_commandn.py"
        self.mainListUri = "http://feeds.feedburner.com/command-n/h264"
#        self.baseUrl = "http://www.net5.nl"
#        self.onUpDownUpdateEnabled = True
        
        self.contextMenuItems = []
#        self.contextMenuItems.append(contextmenu.ContextMenuItem("Update Item", "CtMnUpdateItem", itemTypes="video", completeStatus=None))            
#        self.contextMenuItems.append(contextmenu.ContextMenuItem("Download Item", "CtMnDownloadItem", itemTypes="video", completeStatus=True))
        self.contextMenuItems.append(contextmenu.ContextMenuItem("Play using Mplayer", "CtMnPlayMplayer", itemTypes="video", completeStatus=True))
        self.contextMenuItems.append(contextmenu.ContextMenuItem("Play using DVDPlayer", "CtMnPlayDVDPlayer", itemTypes="video", completeStatus=True))
                
        self.requiresLogon = False
        
#        self.episodeItemRegex = '<div class="thumb">\W+<a[^>]+href="(/[^"]+)"[^>]*>\W+<img[^>]+alt="([^"]+)"/>' # used for the ParseMainList
#        self.episodeItemRegex = '<item>.*<title>([^<]+).*<link>([^<]+).*</item>'   # used for the ParseMainList
#        self.videoItemRegex = '<item>\W+<title>([^<]+)</title>\W+<link>([^<]+)</link>[^]+<pubDate>([^]+)</pubDate>[^]+<itunes:summary>([^]+)</itunes:summary>[^]+</item>'   # used for the CreateVideoItem
#        self.pageNavigationRegex = '<a href="([^"]+)(\d+)"><span>\d+</span></a>' #self.pageNavigationIndicationRegex
#        self.pageNavigationRegexIndex = 1
  
        self.videoItemRegex = '<item>\W+?<title>([^<]+?)</title>\W+?<link>([^<]+?)</link>[^]+?<pubDate>([^]+?)</pubDate>[^]+?summary>([^<]+?)<[^<]+?>[^]+?</item>'
              
        # decrepated. Using url based on ID now
        #self.mediaUrlRegex = '<param name="src" value="([^"]+)" />'    # used for the UpdateVideoItem
        
        return True
      
    #==============================================================================
    # ContextMenu functions
    #==============================================================================
#    def CtMnUpdateItem(self, selectedIndex):
#        logFile.debug('Updating item (Called from ContextMenu)')
#        self.onUpDown(ignoreDisabled = True)
#    
#    def CtMnDownloadItem(self, selectedIndex):
#        item = self.listItems[selectedIndex]
#        self.listItems[selectedIndex] = self.DownloadEpisode(item)

    def CtMnPlayMplayer(self, selectedIndex):
        item = self.listItems[selectedIndex]
        self.PlayVideoItem(item, "mplayer")
    
    def CtMnPlayDVDPlayer(self, selectedIndex):
        item = self.listItems[selectedIndex]
        self.PlayVideoItem(item,"dvdplayer")    

    #==============================================================================
    def ParseMainList(self):

        items = []
        
        item = common.clistItem("Command-N iPod Videos", "http://feeds.feedburner.com/commandN_pod")
        item.icon = self.folderIcon
        items.append(item)
    
        item = common.clistItem("Command-N XViD Videos", "http://feeds.feedburner.com/command-n/xvid")
        item.icon = self.folderIcon
        items.append(item)

        item = common.clistItem("Command-N MPEG-4 Videos", "http://feeds.feedburner.com/command-n/mpeg4")
        item.icon = self.folderIcon
        items.append(item)

        item = common.clistItem("Command-N H-264 Videos", "http://feeds.feedburner.com/command-n/h264")
        item.icon = self.folderIcon
        items.append(item)

        return items

    #==============================================================================
#    def CreateEpisodeItem(self, resultSet):
#        """
#        Accepts an arraylist of results. It returns an item.
#        """
#        logFile.debug('starting CreateEpisodeItem for %s', self.channelName)
#        
#        # dummy class
#        item = common.clistItem(resultSet[1], resultSet[0])
#        item.icon = self.icon
#        item.complete = True
#        return item
    
    #=============================================================================
    def CreateVideoItem(self, resultSet):
        """
        Accepts an arraylist of results. It returns an item.
        """
        logFile.debug('starting CreateVideoItem for %s', self.channelName)
        logFile.debug(resultSet)
        
        item = common.clistItem(resultSet[0], resultSet[1])
        
        item.thumb = self.noImage
        item.icon = self.icon
        item.type = 'video'

#        item.mediaurl = resultSet[1]
#        item.date = resultSet[2]
#        item.description = resultSet[3]
#        logFile.debug('Title: ', self.title, self.channelName)
#        logFile.debug('URL: ', self.url, self.channelName)
#        logFile.debug('Date: ', self.date, self.channelName)
#        logFile.debug('MediaURL: ', self.mediaurl, self.channelName)
#        logFile.debug('Description: ', self.description, self.channelName)

        item.complete = True
        
        return item
    
    #=============================================================================
#    def UpdateVideoItem(self, item):
#        """
#        Accepts an item. It returns an updated item. Usually retrieves the MediaURL
#        and the Thumb! It should return a completed item.
#        """
#        logFile.info('starting UpdateVideoItem for %s (%s)', item.name, self.channelName)
#        
#        #item.thumb = self.CacheThumb(item.thumbUrl)        
#        
#        # now the mediaurl is derived
#        # http://www.garnierstreamingmedia.com/asx/openclip.asp?file=/sbs6/net5/juliastango_S02/juliastango_S02E07.wmv
#        #                                             http://asx.sbsnet.nl/net5/juliastango_S02/juliastango_S02E07.wmv
#        
#        data = uriHandler.Open(item.url, pb=False)
#        urls = common.DoRegexFindAll('<a class="wmv-player-holder" href="(http://asx.sbsnet.nl/net5/)([^"]+)"></a>', data)
#        for url in urls:
#            item.mediaurl = "http://www.garnierstreamingmedia.com/asx/openclip.asp?file=/sbs6/net5/%s" % (url[1])
#        
#        if item.mediaurl != "":
#            logFile.debug("Media url was found: %s", item.mediaurl)
#            item.complete = True
#        else:
#            logFile.debug("Media url was not found.")
#        return item



- Basje - 2008-11-10

^Mask^ Wrote:Hi Basje,

Actually, the code is no different from the one a few posts back. Only thing I have been playing around with is the regex and some of the values captured and stored (ie: comment out things like item.description =, to avoid it complaining about empty regex values).

Because you are not willing to post it there, I will: http://www.pastebin.ca/1250133

That is far more better than pasting the code on a forum. Anyway, there is an error in the the regex in line 71: there was [^]+ in the line and that is wrong! I fixed it (I think), so check it.


- ^Mask^ - 2008-11-10

Hey Basje,

When I click the pastebin link, all I see is an empty page. I think my provider might block access to pastebin. Anyways, will take a look at the regex suggestion and report back!


- ^Mask^ - 2008-11-10

Ok about 20 proxy's did the trick Tongue I tried the updated regex, but unfortunately didnt work:

Code:
20081110 23:05:24 - CRITICAL - common.py        - 102 - error regexing
20081110 23:05:24 - CRITICAL - common.py        - 102 - | Traceback (most recent call last):
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\scripts\XOT-Uzg.v3\resources\libs\common.py", line 99, in DoRegexFindAll
20081110 23:05:24 - CRITICAL - common.py        - 102 - |     result = re.compile(regex, re.DOTALL + re.IGNORECASE)
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 180, in compile
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 227, in _compile
20081110 23:05:24 - CRITICAL - common.py        - 102 - | error: unexpected end of regular expression

I copied and pasted the script you updated and uploaded to pastebin (thanks for that), which included this regex (http://www.pastebin.ca/1250133):

Code:
self.videoItemRegex = '<item>W+?<title>([^<]+?)</title>W+?<link>([^<]+?)</link>[^<]+?<pubDate>([^>]+?)</pubDate>[^>]+?summary>([^<]+?)<[^<]+?>[^]+?</item>'

Any other ideas what this could be? I'm not good at regex's, but starting to understand what its grouping and grabbing.

I really appreciate your efforts to provide me with advice and hope you can help me figure out what's going wrong.


- ^Mask^ - 2008-11-10

This is the actual RSS file for your reference:

http://feeds.feedburner.com/command-n/h264


- Basje - 2008-11-10

^Mask^ Wrote:Ok about 20 proxy's did the trick Tongue I tried the updated regex, but unfortunately didnt work:

Code:
20081110 23:05:24 - CRITICAL - common.py        - 102 - error regexing
20081110 23:05:24 - CRITICAL - common.py        - 102 - | Traceback (most recent call last):
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\scripts\XOT-Uzg.v3\resources\libs\common.py", line 99, in DoRegexFindAll
20081110 23:05:24 - CRITICAL - common.py        - 102 - |     result = re.compile(regex, re.DOTALL + re.IGNORECASE)
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 180, in compile
20081110 23:05:24 - CRITICAL - common.py        - 102 - |   File "Q:\system\python\python24.zlib\sre.py", line 227, in _compile
20081110 23:05:24 - CRITICAL - common.py        - 102 - | error: unexpected end of regular expression

I copied and pasted the script you updated and uploaded to pastebin (thanks for that), which included this regex (http://www.pastebin.ca/1250133):

Code:
self.videoItemRegex = '<item>W+?<title>([^<]+?)</title>W+?<link>([^<]+?)</link>[^<]+?<pubDate>([^>]+?)</pubDate>[^>]+?summary>([^<]+?)<[^<]+?>[^]+?</item>'

Any other ideas what this could be? I'm not good at regex's, but starting to understand what its grouping and grabbing.

I really appreciate your efforts to provide me with advice and hope you can help me figure out what's going wrong.
The regex is still not valid! it still has a [^] group in it.