Пример #1
0
    def _get_show_streams(self,
                          stream_data,
                          show,
                          episode,
                          platform="desktop"):
        video_id = parse_json(stream_data.group(1), schema=self.vod_id_schema)
        res = http.get(self.vod_api,
                       params={
                           "platform": platform,
                           "id": video_id
                       })

        # create a unique list of the stream manifest URLs
        streams = []
        urldups = []
        for stream in parse_xml(res.text, schema=self._vod_api_schema):
            if stream["url"] not in urldups:
                streams.append(stream)
                urldups.append(stream["url"])

        mapper = StreamMapper(lambda fmt, strm: strm["url"].endswith(fmt))
        mapper.map(".m3u8", self._make_hls_hds_stream,
                   HLSStream.parse_variant_playlist)
        mapper.map(".f4m",
                   self._make_hls_hds_stream,
                   HDSStream.parse_manifest,
                   is_akamai=True)
        mapper.map(
            ".mp4", lambda s:
            (s["bitrate"] + "k", HTTPStream(self.session, s["url"])))

        for q, s in mapper(streams):
            yield q, s
Пример #2
0
    def _get_live_streams(self, player):
        mappers = []
        swf_url = SWF_URL
        for playlist in player.get("playlist", []):
            bitrates = playlist.get("bitrates")
            provider = playlist.get("connectionProvider")
            rtmp = None

            if bitrates:
                rtmp = playlist.get("netConnectionUrl")
            elif provider and provider in player["plugins"]:
                provider = player["plugins"][provider]
                swf_name = provider["url"]
                swf_url = SWF_BASE + swf_name
                rtmp = provider["netConnectionUrl"]
                bitrates = player["clip"]["bitrates"]
            else:
                continue

            mapper = StreamMapper(cmp=lambda provider, bitrate: bitrate[
                "provider"].startswith(provider))
            mapper.map("hls", self._create_hls_streams)
            mapper.map("rtmp", self._create_rtmp_stream, rtmp, swf_url)
            mappers.append(mapper(bitrates))

        return chain.from_iterable(mappers)
Пример #3
0
    def _get_video_streams(self, player):
        base_url = player["clip"]["baseUrl"] or VOD_BASE_URL
        mapper = StreamMapper(cmp=lambda ext, bitrate: urlparse(bitrate["url"])
                              .path.endswith(ext))
        mapper.map(".m3u8", self._create_video_stream, HLSStream, base_url)
        mapper.map(".mp4", self._create_video_stream, HTTPStream, base_url)
        mapper.map(".flv", self._create_video_stream, HTTPStream, base_url)

        return mapper(player["clip"]["bitrates"])
Пример #4
0
    def _extract_streams(self, stream_id):
        res = http.get(STREAM_API_URL.format(stream_id),
                       raise_for_status=False)
        stream_info = http.json(res, schema=_stream_schema)

        if stream_info.get("msg"):
            # error message
            self.logger.error(stream_info.get("msg"))
            raise NoStreamsError(self.url)

        mapper = StreamMapper(
            lambda pattern, video: re.search(pattern, video[1]))
        mapper.map(r"/\w+\.m3u8", self._create_dynamic_streams, "HLS",
                   HLSStream.parse_variant_playlist)
        mapper.map(r"/\w+\.f4m", self._create_dynamic_streams, "HDS",
                   HDSStream.parse_manifest)
        mapper.map(r"^rtmp://", self._create_rtmp_stream)

        return mapper(stream_info.items())
Пример #5
0
    def _get_live_stream(self, stream_data, show, episode=None):
        # parse the stream info as json
        stream_info = parse_json(stream_data.group(1), schema=self.live_schema)
        # get the stream ID
        stream_id = None
        show_info = stream_info[u"streams"][show]

        if episode:
            self.logger.debug("Loading replay of episode: {0}/{1}", show,
                              episode)
            for epi in show_info[u"archiveEpisodes"]:
                if epi[u"slug"] == episode:
                    stream_id = epi[u"id"]
        elif show_info.get("isLive") or not len(show_info[u"archiveEpisodes"]):
            self.logger.debug("Loading LIVE streams for: {0}", show)
            stream_id = show_info[u"stream"]
        else:  # off-air
            if len(show_info[u"archiveEpisodes"]):
                epi = show_info[u"archiveEpisodes"][0]
                self.logger.debug("Loading replay of episode: {0}/{1}", show,
                                  epi[u"slug"])
                stream_id = epi[u"id"]
            else:
                self.logger.error("This stream is currently offline")
                return

        if stream_id:
            api_url = self.API_URL.format(id=stream_id)

            res = http.get(api_url,
                           headers={"User-Agent": useragents.SAFARI_8})
            stream_data = http.json(res, schema=self._api_schema)

            mapper = StreamMapper(lambda fmt, surl: surl.endswith(fmt))
            mapper.map(".m3u8", HLSStream.parse_variant_playlist, self.session)
            mapper.map(".f4m", HDSStream.parse_manifest, self.session)

            stream_urls = [
                asset[u"url"]
                for asset in stream_data[u'data'][u'stream'][u'assets']
            ]
            for q, s in mapper(stream_urls):
                yield q, s

        else:
            self.logger.error(
                "Couldn't find the stream ID for this stream: {0}".format(
                    show))
Пример #6
0
    def _get_streams(self):
        # Retrieve URL page and search for new type of video ID
        res = http.get(self.url)
        match = _id_re.search(res.text)

        # Use API if match, otherwise resort to old method
        if match:
            vid = match.group("id")
            res = http.get(API_URL.format(vid))

            videos = http.json(res, schema=_video_schema)
            mapper = StreamMapper(
                cmp=lambda format, video: video["format"] == format)
            mapper.map("hls", self._create_streams, "HLS",
                       HLSStream.parse_variant_playlist)
            mapper.map("hds", self._create_streams, "HDS",
                       HDSStream.parse_manifest)
        else:
            res = http.get(self.url, params=dict(output="json"))
            videos = http.json(res, schema=_old_video_schema)

            mapper = StreamMapper(
                cmp=lambda type, video: video["playerType"] == type)
            mapper.map("ios", self._create_streams, "HLS",
                       HLSStream.parse_variant_playlist)
            mapper.map("flash", self._create_streams, "HDS",
                       HDSStream.parse_manifest)

        return mapper(videos)
Пример #7
0
    def _get_streams(self):
        # Get domain name
        self.domain = _url_re.match(self.url).group('domain')

        # Set header data for user-agent
        hdr = {'User-Agent': USER_AGENT.format('sv_SE')}

        # Parse video ID from data received from supplied URL
        res = http.get(self.url, headers=hdr).text
        match = _videoid_re.search(res)
        if not match:   # Video ID not found
            self.logger.error('Failed to parse video ID')
            return {}
        videoId = match.group('id')

        # Get data from general API to validate that stream is playable
        res = http.get(GENERAL_API_URL.format(self.domain, videoId), headers=hdr)
        data = http.json(res, schema=_api_schema)
        if not data['data']:                # No data item found
            self.logger.error('Unable to find "data" item in general API response')
            return {}
        if not self._is_playable(data):    # Stream not playable
            self.logger.error('Stream is not playable (Premium or DRM-protected content)')
            return {}

        # Get geo data, validate and form cookie consisting of
        # geo data + expiry timestamp (current time + 1 hour)
        res = http.get(GEO_DATA_URL.format(self.domain), headers=hdr)
        geo = http.json(res, schema=_geo_schema)
        timestamp = (int(time.time()) + 3600) * 1000
        cookie = 'dsc-geo=%s' % quote('{"countryCode":"%s","expiry":%s}' % (geo, timestamp))

        # Append cookie to headers
        hdr['Cookie'] = cookie

        # Get available streams using stream API
        try:
            res = http.get(STREAM_API_URL.format(self.domain, videoId, 'hls'),
                           headers=hdr, verify=False)
            data = http.json(res, schema=_media_schema)
            media = data.copy()
            res = http.get(STREAM_API_URL.format(self.domain, videoId, 'hds'),
                           headers=hdr, verify=False)
            data = http.json(res, schema=_media_schema)
            media.update(data)
        except PluginError as err:      # Likely geo-restricted
            if any(e in str(err) for e in ('401 Client Error',
                                           '403 Client Error')):
                self.logger.error('Failed to access stream API, '
                                  'may be due to geo-restriction')
                raise NoStreamsError(self.url)
            else:
                raise

        # Reformat data into list with stream format and url
        streams = [{'format': k, 'url': media[k]} for k in media]

        # Create mapper for supported stream types (HLS/HDS)
        mapper = StreamMapper(cmp=lambda type, video: video['format'] == type)
        mapper.map('hls', self._create_streams, HLSStream.parse_variant_playlist)
        mapper.map('hds', self._create_streams, HDSStream.parse_manifest)

        # Feed stream data to mapper and return all streams found
        return mapper(streams)