Example #1
0
 def _createM3uFile(self,channelsList,userDataPath):
     try:
         if not os.path.exists(userDataPath):
             os.makedirs(userDataPath)
 
         if not channelsList:
             raise FreeboxHandlerError('channel list is empty channelsList:')
             
         with io.open(userDataPath+'freebox.m3u', 'w', encoding='utf-8') as the_file:
             m3uhead = u'#EXTM3U\r\n'
             the_file.write(m3uhead)                
             for dChannel in channelsList:
                 m3uFormat = "#EXTINF:-1 channel-id=\"%d\" tvg-id=\"%s\" tvg-name=\"%s\" tvg-logo=\"%s\" group-title=\"%s\",%s\r\n%s\r\n"
                 m3uline = m3uFormat % (
                     dChannel['number'],
                     dChannel['channelId'], 
                     dChannel['shortname'].replace(" ", "_"), 
                     dChannel['logo'], 
                     dChannel['group'], 
                     dChannel['name'], 
                     dChannel['stream']
                 )
                 the_file.write(m3uline)
             return True
     except Exception, e:
         raise FreeboxHandlerError(str(e))
Example #2
0
 def _requestJsonData(self, url):
     apiResponse = requests.get(self.apiUrl + url , headers={'X-Fbx-App-Auth': self.session} , verify=self.certPath)
     if apiResponse.ok:
         jData = json.loads(apiResponse.content)
         if jData['success'] == True:
             return jData['result']
         raise FreeboxHandlerError('API '+url+' Not answered as intended - HTTP Status:'+str(apiResponse.status_code)+'-'+str(jData['msg'].encode('utf-8')))
     raise FreeboxHandlerError('API '+url+' Not answered as intended - HTTP Status:'+str(apiResponse.status_code))
Example #3
0
 def _checkBouquetId(self):
     try:
         jData = self._requestJsonData('/tv/bouquets/')
         for bouquet in jData:
             if bouquet['name'] == self.bouquetName:
                 self.bouquetId = bouquet['id']
         # if no ID returned, it must because they changed the name, so please report issue to update code
         if not self.bouquetId:
             raise FreeboxHandlerError('Bouquet Name seems to have changed report the issue this need to update code')
     except Exception as e:
         raise FreeboxHandlerError('jData:'+str(jData)+' bouquet:'+str(bouquet))
Example #4
0
 def _checkApiVersion(self):
     apiResponse = requests.get(self.apiUrl + '/api_version', verify=self.certPath)
     jData = json.loads(apiResponse.content)
     if apiResponse.ok and format(len(jData)) > 0:
         jData = json.loads(apiResponse.content)
         if LooseVersion(jData['api_version']) >= '3.0':
             return True
         raise FreeboxHandlerError('FreeBox API not compatible')
         return False
     else:
         raise FreeboxHandlerError('FreeBox API not answered - HTTP Status:'+apiResponse.status_code)
         return False
Example #5
0
 def _getSession(self):
     if not (self.appToken and self.challenge):
         raise FreeboxHandlerError('missing value appToken:'+self.appToken+" challenge:"+self.challenge)
     hashed = hmac.new(self.appToken, self.challenge, hashlib.sha1)
     payload = { 'app_id': self.appId, 'password': hashed.hexdigest() }
     data = json.dumps(payload)
     apiResponse = requests.post(self.apiUrl + '/login/session/', data, verify=self.certPath)
     jData = json.loads(apiResponse.content)
     if jData['success'] == True:
         self.session = jData['result']['session_token']
         return True
     raise FreeboxHandlerError('Get Session - ' + str(jData['msg'].encode('utf-8') + "appToken:"+self.appToken+" challenge:"+self.challenge.encode('utf-8')))
     return False
Example #6
0
    def _filterAndSortChannels(self,channelsList, streamsList):
        lChannels = []
        for channelId in channelsList:
            # we filter channel and don't process unavailable channels
            if channelsList[channelId]['available'] == True:
                # we get the stream uri for the channel in choosed quality and the channel number in same time
                channelNumber = ''
                rtspUrl = ''

                try:
                    streamChannel = (item for item in streamsList if item["uuid"] == channelsList[channelId]['uuid']).next()
                except StopIteration as e:
                    xbmc.log('[FREEBOXTV] no stream found for '+str(channelsList[channelId]['uuid'])+' - '+channelsList[channelId]['name'], xbmc.LOGWARNING)
                # if the channel is not a pub_service, the rtsp is always missing
                if streamChannel['pub_service'] == True:
                    channelNumber = streamChannel['number']
                   
                    # we prepare a dict of stream uri & quality available for the channel
                    lStream = {}
                    for stream in streamChannel['streams']:
                        lStream[stream['quality']] = stream['rtsp']
                        #we search for the nearest of choosed one quality available
                    tmpQuality = self.quality
                    while tmpQuality not in lStream:
                        tmpQuality = self._getLowerQuality(tmpQuality)
                        if not tmpQuality:
                            raise FreeboxHandlerError("Quality unexpected with uuid:"+uuid)
                    rtspUrl = lStream[tmpQuality]
                # we process the channel only if a stream uri is returned
                if rtspUrl:
                    dChannel = {
                        'channelId':channelsList[channelId]['uuid'].replace('-','.'),
                        'number':channelNumber,
                        'name':channelsList[channelId]['name'],
                        'shortname':channelsList[channelId]['short_name'], 
                        'logo':self.apiUrl.split('/api')[0]+channelsList[channelId]['logo_url'], 
                        'group':self.bouquetName,
                        'stream':rtspUrl,
                        #'quality':quality
                    }
                    lChannels.append(dChannel)
                if len(lChannels)<=0:
                    raise FreeboxHandlerError("List is empty")
        # we sort the channels list by their official number in the bouquet
        finalChannelsList = sorted(lChannels, key=lambda lChannels: lChannels['number'])

        # We give some feedback to the user
        xbmc.executebuiltin('Notification(FreeboxTV, filtered %d channels on total of %d, %d )' % ( len(finalChannelsList), len(channelsList), 5000))
        return finalChannelsList
Example #7
0
 def _checkPairing(self, trackId):
     apiResponse = requests.get(self.apiUrl + '/login/authorize/' + trackId, verify=self.certPath)
     jData = json.loads(apiResponse.content)
     if not apiResponse.ok and jData['success'] == True:
         raise FreeboxHandlerError(jData['msg'])
     # get the challenge token needed for getting login session
     if jData['result']['status'] == 'granted':
         self.challenge = jData['result']['challenge']
         return True
     if jData['result']['status'] == 'unknown' or jData['result']['status'] == 'denied':
         #TODO: return false to display a popup saying to user to authorize pairing on their freebox
         raise FreeboxHandlerError('Pairing Revoked')
     if jData['result']['status'] == 'pending' or jData['result']['status'] == 'timeout':
         #TODO: return false to display a popup saying to user to authorize pairing on their freebox
         raise FreeboxHandlerError('User not confirmed authorization')
     return False
Example #8
0
 def _pairingWithFreebox(self):
     import socket
     payload = {'app_id': self.appId,
        'app_name': self.appName,
        'app_version': self.appVersion,
        'device_name': self.deviceName
        }
     payload = json.dumps(payload)
     apiResponse = requests.post(self.apiUrl + '/login/authorize/', data=payload, verify=self.certPath)
     jData = json.loads(apiResponse.content)
     if not apiResponse.ok and jData['success'] == True:
         raise FreeboxHandlerError('ERROR: ' + jData['msg'])
     self.appToken = jData['result']['app_token']
     self.trackId = jData['result']['track_id']
     return (self.appToken, self.trackId)
Example #9
0
    def createXmlTvFile(self,channelsList,userDataPath):
        from jsonmerge import merge
        
        if not channelsList:
            raise FreeboxHandlerError('channel list is empty channelsList:')
        
        xmltvLine = (   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
                        "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\r\n\r\n"
                        "<tv source-info-url=\"http://www.schedulesdirect.org/\" source-info-name=\"Schedules Direct\""
                        " generator-info-name=\"XMLTV/$Id: tv_grab_na_dd.in,v 1.70 2008/03/03 15:21:41 rmeden Exp"
                        " $\" generator-info-url=\"http://www.xmltv.org/\">\r\n"
                    )

        channelNumber = 0
        for channel in channelsList:
            channelNumber = channelNumber+1
            xmltvLine += (
                "   <channel id=\"%s\">\r\n"
                "       <display-name>%s</display-name>\r\n"
                "       <icon src=\"%s\" />\r\n"
                "   </channel>\r\n"
                ) % (channel['channelId'], channel['name'], channel['logo'])
        
        addTime = 0
        programsList = {}
        os.environ['TZ'] = 'Europe/Paris'
        
        for i in range(0,24): # on interroge toute la journée
            addTime = 0
            nowHour = int(time.strftime("%H"))
            deltaHour = i - nowHour
            if deltaHour >= 0: # enfin sauf les heures passés, osef
                if i > 0:
                    addTime = deltaHour*3600
    
                epoch = int(time.mktime(time.localtime())) + addTime
                xbmc.log('epoch:'+str(epoch)+' meaning:'+time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(epoch)),xbmc.LOGWARNING)
                
                programsList = merge( programsList, self._requestJsonData('/tv/epg/by_time/'+str(epoch)) )
        
        programmNumber = 0
        channelProgramNumber = 0
        for channelId,lChannel in programsList.iteritems():
            channelProgramNumber = channelProgramNumber +1
            
            for programId,lProgram in lChannel.iteritems():
                programmNumber = programmNumber+1

                programStartTS = int(lProgram['date'])
                programEndTS = int(programStartTS) + int(lProgram['duration'])

                # We want to write program only for channel we display not the unavailable channel
                if any(d['channelId'] == channelId.replace('-','.') for d in channelsList):
                    xmltvLine += (
                        "   <programme start=\"%s\" stop=\"%s\" channel=\"%s\">\r\n"
                        ) % (
                        #Freebox give local timestamp, need to convert it to gmt timestamp for xmltv
                        # and forget timezone offset it mess up all
                        time.strftime('%Y%m%d%H%M%S -0100', time.localtime( programStartTS - 14400) ),
                        time.strftime('%Y%m%d%H%M%S -0100', time.localtime( programEndTS - 14400 ) ),
                        channelId.replace('-','.')
                        )
                    if 'title' in lProgram:
                        xmltvLine += "      <title>%s</title>\r\n" % lProgram['title']

                    if 'category_name' in lProgram:
                        xmltvLine += "      <category>%s</category>\r\n" % lProgram['category_name']

                    if 'sub_title' in lProgram:
                        xmltvLine += "      <sub-title>%s</sub-title>\r\n" % lProgram['sub_title']

                    if 'episode_number' in lProgram:
                        if not 'season_number' in lProgram:
                            xmltvLine += "      <episode-num system=\"xmltv_ns\">%d</episode-num>\r\n" % lProgram['episode_number']
                        else:
                            xmltvLine += "      <episode-num system=\"xmltv_ns\">%d.%d</episode-num>\r\n"  % (lProgram['season_number'], lProgram['episode_number']) 

                    xmltvLine += '   </programme>\r\n'
                
        xmltvLine += '</tv>'
        
        with io.open(userDataPath+'freebox.xml', 'w', encoding='utf-8') as the_file:
            the_file.write(xmltvLine)

        xbmc.executebuiltin('Notification(FreeboxTV, M3U & XMLTV Wrote sucessfully, all is ready!,5000 )')
        xbmc.log('[FREEBOXTV]XMLTV wrote- channels:'+str(channelNumber)+' channels For Program:'+str(channelProgramNumber)+' program:'+str(programmNumber),xbmc.LOGWARNING)
        return True