예제 #1
0
 def downloadWebData(self, url, headers=None):
     for _ in range(MAX_RETRIES):
         try:
             req = Request(url)
             req.add_header(Keys.USER_AGENT, Keys.USER_AGENT_STRING)
             if headers:
                 for key, value in headers.iteritems():
                     req.add_header(key, value)
             response = urlopen(req)
             if sys.version_info < (3, 0):
                 data = response.read().decode('utf-8')
             else:
                 data = response.readall().decode('utf-8')
             response.close()
             break
         except Exception as err:
             if not isinstance(err, URLError):
                 self.logger.debug("Error %s during HTTP Request, abort",
                                   repr(err))
                 raise  # propagate non-URLError
             self.logger.debug("Error %s during HTTP Request, retrying",
                               repr(err))
     else:
         raise TwitchException(TwitchException.HTTP_ERROR)
     return data
예제 #2
0
    def getJson(self, url, headers=None):
        def getClientID():
            # return a Client ID to use for Twitch API
            client_id = Addon().getSetting(
                'oauth_client_id')  # get from settings
            if not client_id:  # not in settings
                try:
                    client_id = b64decode(Keys.CLIENT_ID)  # use Keys.CLIENT_ID
                except:
                    client_id = ''
            return client_id

        if not headers:
            headers = {}
        # Set api version and client id headers
        headers.setdefault(Keys.ACCEPT, Keys.API_VERSION)
        headers.setdefault(Keys.CLIENT_ID_HEADER, getClientID())

        jsonString = self.downloadWebData(url, headers)
        try:
            jsonDict = json.loads(jsonString)
            self.logger.debug(json.dumps(jsonDict, indent=4, sort_keys=True))
            return jsonDict
        except:
            raise TwitchException(TwitchException.JSON_ERROR)
예제 #3
0
    def __init__(self, data, qualityList=None):
        self.playlist = dict()
        self.qualityList = qualityList or Keys.QUALITY_LIST_STREAM

        def parseQuality(ExtXMediaLine, ExtXStreamInfLine, Url):
            # find name of current quality, NAME=", 6 chars
            namePosition = ExtXMediaLine.find('NAME')
            if namePosition == -1:
                raise TwitchException(TwitchException.NO_PLAYABLE)
            qualityString = ''
            namePosition += 6
            for char in ExtXMediaLine[namePosition:]:
                if char == '"':
                    break
                qualityString += char
            return qualityString, Url

        lines = data.splitlines()
        linesIterator = iter(lines)
        for line in linesIterator:
            if line.startswith('#EXT-X-MEDIA'):
                quality, url = parseQuality(line, next(linesIterator),
                                            next(linesIterator))
                qualityInt = self.qualityList.index(quality)
                self.playlist[qualityInt] = url
        if not self.playlist:
            # playlist dict is empty
            raise TwitchException(TwitchException.NO_PLAYABLE)
예제 #4
0
 def getStreamInfo(self, channelname):
     # Get Stream info
     url = ''.join([Urls.STREAMS, channelname])
     stream = self._fetchItems(url, Keys.STREAM)
     if stream:
         return stream
     else:
         raise TwitchException(TwitchException.STREAM_OFFLINE)
예제 #5
0
 def parseQuality(ExtXMediaLine, ExtXStreamInfLine, Url):
     # find name of current quality, NAME=", 6 chars
     namePosition = ExtXMediaLine.find('NAME')
     if namePosition == -1:
         raise TwitchException(TwitchException.NO_PLAYABLE)
     qualityString = ''
     namePosition += 6
     for char in ExtXMediaLine[namePosition:]:
         if char == '"':
             break
         qualityString += char
     return qualityString, Url
예제 #6
0
    def getLiveStream(self, channelName, maxQuality):
        # Get Access Token (not necessary at the moment but could come into effect at any time)
        tokenurl = Urls.CHANNEL_TOKEN.format(channelName)
        channeldata = self.scraper.getJson(tokenurl)
        channeltoken = channeldata[Keys.TOKEN]
        channelsig = channeldata[Keys.SIG]

        # Download and Parse Multiple Quality Stream Playlist
        try:
            hls_url = Urls.HLS_PLAYLIST.format(channelName, channelsig, channeltoken)
            data = self.scraper.downloadWebData(hls_url)
            playlist = M3UPlaylist(data)
            return playlist.getQuality(maxQuality)

        except TwitchException:
            # HTTP Error in download web data -> stream is offline
            raise TwitchException(TwitchException.STREAM_OFFLINE)
예제 #7
0
def playVideo(_id, quality):
    """
    :param _id: string: video id
    :param quality: string: qualities[quality]
    0 = Source, 1 = 1080p60, 2 = 1080p30, 3 = 720p60, 4 = 720p30, 5 = 540p30, 6 = 480p30, 7 = 360p30, 8 = 240p30, 9 = 144p30
    -1 = Choose quality dialog
    * any other value for quality will use addon setting
    """
    videoQuality = utils.getVideoQuality(quality)
    oauthtoken = utils.getOauthToken()
    if videoQuality != -1:
        # videoQuality == -1 if quality dialog was cancelled
        videoInfo = CONVERTER.getVideoInfo(TWITCHTV.getVideo(_id))
        simplePlaylist = TWITCHTV.getVideoPlaylist(_id, videoQuality, oauthtoken)
        playlistItems = PLAYLIST_CONVERTER.convertToXBMCPlaylist(simplePlaylist, videoInfo.get('title', ''),
                                                                 videoInfo.get('thumbnail', ''))
        if playlistItems != ():
            (playlist, listItem) = playlistItems
            utils.play(listItem.get('path', ''), listItem)
        else:
            raise TwitchException(TwitchException.NO_PLAYABLE)
예제 #8
0
    def __init__(self, data, qualityList=None):
        self.playlist = dict()
        self.qualityList = qualityList or Keys.QUALITY_LIST_STREAM

        def parseQuality(ExtXMediaLine, ExtXStreamInfLine, Url):
            # find name of current quality, NAME=", 6 chars
            namePosition = ExtXMediaLine.find('NAME')
            if namePosition == -1:
                raise TwitchException(TwitchException.NO_PLAYABLE)
            qualityString = ''
            namePosition += 6
            for char in ExtXMediaLine[namePosition:]:
                if char == '"':
                    break
                qualityString += char
            return qualityString, Url

        lines = data.splitlines()
        linesIterator = iter(lines)
        for line in linesIterator:
            if line.startswith('#EXT-X-MEDIA:TYPE=VIDEO'):
                quality, url = parseQuality(line, next(linesIterator),
                                            next(linesIterator))
                # do coercing of qualities here
                if quality not in self.qualityList:  # non-standard quality naming, attempt to coerce
                    if quality.endswith('p'):  # '1080p'
                        quality += '30'  # '1080p30' is in qualityList
                    else:
                        quality = quality.split(
                            None, 1
                        )  # '1080p60 - source' -> ['1080p60', ' - source']
                        if quality:
                            quality = quality[0]  # '1080p60' is in qualityList
                if quality in self.qualityList:  # check for quality in list before using it
                    qualityInt = self.qualityList.index(quality)
                    self.playlist[qualityInt] = url
        if not self.playlist:
            # playlist dict is empty
            raise TwitchException(TwitchException.NO_PLAYABLE)
예제 #9
0
def playVideo(_id, quality):
    """
    :param _id: string: video id
    :param quality: string: qualities[quality]
    qualities = {'-1': -1, '0': 0, '1': 1, '2': 2, '3': 3, '4': 4}
    0 = Best, 1 = 720, 2 = 480, 3 = 360, 4 = 226,
    -1 = Choose quality dialog
    * any other value for quality will use addon setting
    """
    videoQuality = utils.getVideoQuality(quality)
    if videoQuality != -1:
        # videoQuality == -1 if quality dialog was cancelled
        videoInfo = CONVERTER.getVideoInfo(TWITCHTV.getVideo(_id))
        simplePlaylist = TWITCHTV.getVideoPlaylist(_id, videoQuality)
        playlistItems = PLAYLIST_CONVERTER.convertToXBMCPlaylist(
            simplePlaylist, videoInfo.get('title', ''),
            videoInfo.get('thumbnail', ''))
        if playlistItems != ():
            (playlist, listItem) = playlistItems
            utils.play(listItem.get('path', ''), listItem)
        else:
            raise TwitchException(TwitchException.NO_PLAYABLE)
예제 #10
0
 def parseQuality(ExtXMediaLine, ExtXStreamInfLine, Url):
     # find name of current quality, NAME=", 6 chars
     namePosition = ExtXMediaLine.find('NAME')
     if namePosition == -1:
         raise TwitchException(TwitchException.NO_PLAYABLE)
     qualityString = ''
     namePosition += 6
     for char in ExtXMediaLine[namePosition:]:
         if char == '"':
             break
         qualityString += char
     groupPosition = ExtXMediaLine.find('GROUP-ID')
     if namePosition == -1:
         group_id = 'unknown'
     else:
         group_id = ''
         groupPosition += 10
         for char in ExtXMediaLine[groupPosition:]:
             if char == '"':
                 break
             group_id += char
     return group_id, qualityString, Url
예제 #11
0
    def __init__(self, data, qualityList=None):
        self.playlist = dict()
        self.qualityList = qualityList or Keys.QUALITY_LIST_STREAM

        def parseQuality(ExtXMediaLine, ExtXStreamInfLine, Url):
            # find name of current quality, NAME=", 6 chars
            namePosition = ExtXMediaLine.find('NAME')
            if namePosition == -1:
                raise TwitchException(TwitchException.NO_PLAYABLE)
            qualityString = ''
            namePosition += 6
            for char in ExtXMediaLine[namePosition:]:
                if char == '"':
                    break
                qualityString += char
            groupPosition = ExtXMediaLine.find('GROUP-ID')
            if namePosition == -1:
                group_id = 'unknown'
            else:
                group_id = ''
                groupPosition += 10
                for char in ExtXMediaLine[groupPosition:]:
                    if char == '"':
                        break
                    group_id += char
            return group_id, qualityString, Url

        source = None
        lines = data.splitlines()
        linesIterator = iter(lines)
        qualityMap = {'high': 1, 'medium': 2, 'low': 3, 'mobile': 4}
        for line in linesIterator:
            if line.startswith('#EXT-X-MEDIA:TYPE=VIDEO'):
                group_id, quality, url = parseQuality(line,
                                                      next(linesIterator),
                                                      next(linesIterator))
                if group_id == 'chunked':
                    source = url
                # do coercing of qualities here
                if quality not in self.qualityList:  # non-standard quality naming, attempt to coerce
                    if quality.endswith('p'):  # '1080p'
                        quality += '30'  # '1080p30' is in qualityList
                    else:
                        quality = quality.split(
                            None, 1
                        )  # '1080p60 - source' -> ['1080p60', ' - source']
                        if quality:
                            quality = quality[0]  # '1080p60' is in qualityList
                if quality in self.qualityList:  # check for quality in list before using it
                    qualityInt = self.qualityList.index(quality)
                    self.playlist[qualityInt] = url
                elif quality.lower(
                ) in qualityMap:  # check for quality in list before using it
                    qualityInt = qualityMap[quality.lower()]
                    self.playlist[qualityInt] = url

        if (source) and (0 not in self.playlist):
            self.playlist[0] = source
        if not self.playlist:
            # playlist dict is empty
            raise TwitchException(TwitchException.NO_PLAYABLE)