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())
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')
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