Пример #1
0
 def test_http_stream(self):
     expected = "http://test.se/stream"
     stream = HTTPStream(self.session, expected)
     self.assertEqual(expected, stream_to_url(stream))
     self.assertEqual(expected, stream.to_url())
Пример #2
0
    def _get_streams(self):
        # Retrieve geolocation data
        res = http.get(self.GEO_URL)
        geo = http.json(res, schema=self._geo_schema)
        country_code = geo['reponse']['geo_info']['country_code']

        # Retrieve URL page and search for video ID
        res = http.get(self.url)
        if 'france.tv' in self.url:
            match = self._pluzz_video_id_re.search(res.text)
        elif 'ludo.fr' in self.url or 'zouzous.fr' in self.url:
            match = self._jeunesse_video_id_re.search(res.text)
        elif 'france3-regions.francetvinfo.fr' in self.url:
            match = self._f3_regions_video_id_re.search(res.text)
        elif 'sport.francetvinfo.fr' in self.url:
            match = self._sport_video_id_re.search(res.text)
        if match is None:
            return
        video_id = match.group('video_id')

        # Retrieve SWF player URL
        swf_url = None
        res = http.get(self.PLAYER_GENERATOR_URL)
        player_url = update_scheme(
            self.url,
            http.json(res, schema=self._player_schema)['result'])
        res = http.get(player_url)
        match = self._swf_re.search(res.text)
        if match is not None:
            swf_url = update_scheme(self.url, match.group(0))

        res = http.get(self.API_URL.format(video_id))
        videos = http.json(res, schema=self._api_schema)
        now = time.time()

        offline = False
        geolocked = False
        drm = False
        expired = False

        streams = []
        for video in videos['videos']:
            video_url = video['url']

            # Check whether video format is available
            if video['statut'] != 'ONLINE':
                offline = offline or True
                continue

            # Check whether video format is geo-locked
            if video['geoblocage'] is not None and country_code not in video[
                    'geoblocage']:
                geolocked = geolocked or True
                continue

            # Check whether video is DRM-protected
            if video['drm']:
                drm = drm or True
                continue

            # Check whether video format is expired
            available = False
            for interval in video['plages_ouverture']:
                available = (interval['debut'] or 0) <= now <= (interval['fin']
                                                                or sys.maxsize)
                if available:
                    break
            if not available:
                expired = expired or True
                continue

            # TODO: add DASH streams once supported
            if '.mpd' in video_url:
                continue

            if '.f4m' in video_url or 'france.tv' in self.url:
                res = http.get(self.TOKEN_URL.format(video_url))
                video_url = res.text

            if '.f4m' in video_url and swf_url is not None:
                for bitrate, stream in HDSStream.parse_manifest(
                        self.session, video_url, is_akamai=True,
                        pvswf=swf_url).items():
                    # HDS videos with data in their manifest fragment token
                    # doesn't seem to be supported by HDSStream. Ignore such
                    # stream (but HDS stream having only the hdntl parameter in
                    # their manifest token will be provided)
                    pvtoken = stream.request_params['params'].get(
                        'pvtoken', '')
                    match = self._hds_pv_data_re.search(pvtoken)
                    if match is None:
                        streams.append((bitrate, stream))
            elif '.m3u8' in video_url:
                for stream in HLSStream.parse_variant_playlist(
                        self.session, video_url).items():
                    streams.append(stream)
            # HBB TV streams are not provided anymore by France Televisions
            elif '.mp4' in video_url and '/hbbtv/' not in video_url:
                match = self._mp4_bitrate_re.match(video_url)
                if match is not None:
                    bitrate = match.group('bitrate')
                else:
                    # Fallback bitrate (seems all France Televisions MP4 videos
                    # seem have such bitrate)
                    bitrate = '1500k'
                streams.append((bitrate, HTTPStream(self.session, video_url)))

        if self.get_option("mux_subtitles") and videos['subtitles'] != []:
            substreams = {}
            for subtitle in videos['subtitles']:
                # TTML subtitles are available but not supported by FFmpeg
                if subtitle['format'] == 'ttml':
                    continue
                substreams[subtitle['type']] = HTTPStream(
                    self.session, subtitle['url'])

            for quality, stream in streams:
                yield quality, MuxedStream(self.session,
                                           stream,
                                           subtitles=substreams)
        else:
            for stream in streams:
                yield stream

        if offline:
            self.logger.error(
                'Failed to access stream, may be due to offline content')
        if geolocked:
            self.logger.error(
                'Failed to access stream, may be due to geo-restricted content'
            )
        if drm:
            self.logger.error(
                'Failed to access stream, may be due to DRM-protected content')
        if expired:
            self.logger.error(
                'Failed to access stream, may be due to expired content')
Пример #3
0
    def _get_streams(self):
        match = _url_id_re.search(self.url)

        video_id = None

        # We can get the VGTV ID directly from vgtv.no URLs
        if match:
            video_id = match.group(1)

        # If we can't, we need to get the VGTV ID from the page content
        else:
            res = http.get(self.url)
            match = _content_id_re.search(res.text)
            if match:
                video_id = match.group(1)

        if not video_id:
            return

        # Now fetch video information
        self.logger.debug("Fetching video info for ID {0}", video_id)
        res = http.get(INFO_URL, params=dict(id=video_id))
        info = http.json(res, schema=_video_schema)

        streams = {}

        # At the time of writing, The previously fetched JSON doesn't
        # point to playlist/manifest files, but to individual stream
        # variants. Based on the provided variants, however, we can
        # build the playlist URLs ourselves.

        # HDS/HLS: Get all variants and produce a playlist URL.
        for f in ('hds', 'hls'):
            if f not in info["formats"]:
                next

            if "mp4" not in info["formats"][f]:
                next

            streamtype = STREAM_TYPES[f]
            f_streams = {}
            hmac = ""

            # Get variants.
            for stream in info["formats"][f]["mp4"]:
                for p in stream["paths"]:
                    url = self._build_url(**p)
                    variant = p["filename"][:-4]  # strip ".mp4"

                    if url in f_streams:
                        f_streams[url].append(variant)
                    else:
                        f_streams[url] = [variant]

                    if p["application"]:
                        hmac = "?hdnea={0}&hdcore?3.1.0".format(
                            p["application"]
                        )

            # Make playlist URL and pass to parser.
            for url, variants in f_streams.items():
                playlist = "{0}/,{1},.mp4.csmil/{2}{3}".format(
                    url,
                    ",".join(variants),
                    streamtype["file"],
                    hmac
                )
                parser = streamtype["parser"]
                params = streamtype.get("params") or {}

                try:
                    streams.update(parser(self.session, playlist, **params))
                except IOError as err:
                    self.logger.error("Failed to extract {0} streams: {1}",
                                      f.upper(), err)

        # HTTP: Also make direct content URLs available for use.
        http_formats = info["formats"].get("http")
        if http_formats and "mp4" in http_formats:
            for stream in http_formats["mp4"]:
                p = stream["paths"][0]
                url = "{0}/{1}".format(self._build_url(**p), p["filename"])
                stream_name = "http_{0}k".format(stream["bitrate"])
                streams[stream_name] = HTTPStream(self.session, url)

        return streams