Ejemplo n.º 1
0
    def _create_adaptive_streams(self, info, streams, protected):
        adaptive_streams = {}
        best_audio_itag = None

        # Extract audio streams from the DASH format list
        for stream_info in info.get("adaptive_fmts", []):
            if stream_info.get("s"):
                protected = True
                continue

            stream_params = dict(parse_qsl(stream_info["url"]))
            if "itag" not in stream_params:
                continue
            itag = int(stream_params["itag"])
            # extract any high quality streams only available in adaptive formats
            adaptive_streams[itag] = stream_info["url"]

            stream_type, stream_format = stream_info["type"]
            if stream_type == "audio":
                stream = HTTPStream(self.session, stream_info["url"])
                name = "audio_{0}".format(stream_format)
                streams[name] = stream

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in self.adp_video.items():
                if itag in adaptive_streams:
                    vurl = adaptive_streams[itag]
                    log.debug("MuxedStream: v {video} a {audio} = {name}".format(
                        audio=best_audio_itag,
                        name=name,
                        video=itag,
                    ))
                    streams[name] = MuxedStream(self.session,
                                                HTTPStream(self.session, vurl),
                                                HTTPStream(self.session, aurl))

        return streams, protected
Ejemplo n.º 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 'pluzz.francetv.fr' in self.url:
            video_re = self._pluzz_video_id_re
        else:
            video_re = self._other_video_id_re
        match = video_re.search(res.text)
        if match is None:
            return
        catalogue = 'Pluzz'
        video_id = match.group('video_id')
        if 'catalogue' in match.groupdict():
            catalogue = match.group('catalogue')

        # Retrieve SWF player URL
        match = self._player_re.search(res.text)
        swf_url = None
        if match is not None:
            player_url = 'http:' + match.group('player')
            res = http.get(player_url)
            match = self._swf_re.search(res.text)
            if match is not None:
                swf_url = os.path.dirname(player_url) + match.group('swf')

        res = http.get(self.API_URL.format(video_id, catalogue))
        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 catalogue == 'Pluzz' or '.f4m' in video_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, 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')
Ejemplo n.º 3
0
    def _get_streams(self):
        # Retrieve geolocation data
        res = self.session.http.get(self.GEO_URL)
        geo = self.session.http.json(res, schema=self._geo_schema)
        country_code = geo['reponse']['geo_info']['country_code']
        log.debug('Country: {0}'.format(country_code))

        # Retrieve URL page and search for video ID
        res = self.session.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 'sport.francetvinfo.fr' in self.url:
            match = self._sport_video_id_re.search(res.text)
        else:
            match = self._embed_video_id_re.search(res.text)
        if match is None:
            return
        video_id = match.group('video_id')
        log.debug('Video ID: {0}'.format(video_id))

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

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

        streams = []
        for video in videos['videos']:
            log.trace('{0!r}'.format(video))
            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

            res = self.session.http.get(self.TOKEN_URL.format(video_url))
            video_url = res.text

            if '.mpd' in video_url:
                # Get redirect video URL
                res = self.session.http.get(res.text)
                video_url = res.url
                for bitrate, stream in DASHStream.parse_manifest(self.session,
                                                                 video_url).items():
                    streams.append((bitrate, stream))
            elif '.f4m' in video_url:
                for bitrate, stream in HDSStream.parse_manifest(self.session,
                                                                video_url,
                                                                is_akamai=True,
                                                                pvswf=self.SWF_PLAYER_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:
            log.error('Failed to access stream, may be due to offline content')
        if geolocked:
            log.error('Failed to access stream, may be due to geo-restricted content')
        if drm:
            log.error('Failed to access stream, may be due to DRM-protected content')
        if expired:
            log.error('Failed to access stream, may be due to expired content')
Ejemplo n.º 4
0
    def ytdl_fallback(self):
        '''Basic support for m3u8 URLs with youtube-dl'''
        log.debug('Fallback youtube-dl')

        class YTDL_Logger(object):
            def debug(self, msg):
                log.debug(msg)

            def warning(self, msg):
                log.warning(msg)

            def error(self, msg):
                log.trace(msg)

        ydl_opts = {
            'call_home': False,
            'forcejson': True,
            'logger': YTDL_Logger(),
            'no_color': True,
            'noplaylist': True,
            'no_warnings': True,
            'verbose': False,
            'quiet': True,
        }

        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            try:
                info = ydl.extract_info(self.url, download=False)
            except Exception:
                return

            if not info or not info.get('formats'):
                return

        self.title = info['title']

        streams = []
        for stream in info['formats']:
            if stream['protocol'] in ['m3u8', 'm3u8_native'
                                      ] and stream['ext'] == 'mp4':
                log.trace('{0!r}'.format(stream))
                name = stream.get('height') or stream.get('width')
                if name:
                    name = '{0}p'.format(name)
                    streams.append((name,
                                    HLSStream(self.session,
                                              stream['url'],
                                              headers=stream['http_headers'])))

        if not streams:
            if ('youtube.com' in self.url and info.get('requested_formats')
                    and len(info.get('requested_formats')) == 2
                    and MuxedStream.is_usable(self.session)):
                audio_url = audio_format = video_url = video_format = video_name = None
                for stream in info.get('requested_formats'):
                    if not stream.get('height'):
                        audio_url = stream.get('url')
                        audio_format = stream.get('format_id')
                    if stream.get('height'):
                        video_url = stream.get('url')
                        video_format = stream.get('format_id')
                        video_name = '{0}p'.format(stream.get('height'))

                log.debug('MuxedStream: v {video} a {audio} = {name}'.format(
                    audio=audio_format,
                    name=video_name,
                    video=video_format,
                ))
                streams.append(
                    (video_name,
                     MuxedStream(
                         self.session,
                         HTTPStream(self.session,
                                    video_url,
                                    headers=stream['http_headers']),
                         HTTPStream(self.session,
                                    audio_url,
                                    headers=stream['http_headers']))))
        return streams
Ejemplo n.º 5
0
    def _get_streams(self):
        self.session.http.headers = {"User-Agent": useragents.CHROME}
        res = self.session.http.get(self.url)

        # remap en to english, and ja to japanese
        rlanguage = {
            "en": "english",
            "ja": "japanese"
        }.get(
            self.get_option("language").lower(),
            self.get_option("language").lower())
        if "_Incapsula_Resource" in res.text:
            log.error("This page is protected by Incapsula, please see "
                      "https://github.com/streamlink/streamlink/issues/2088"
                      " for a workaround.")
            return

        if "Out of Territory" in res.text:
            log.error(
                "The content requested is not available in your territory.")
            return

        id_m = self.experience_id_re.search(res.text)
        experience_id = id_m and int(id_m.group(1))
        if experience_id:
            log.debug(f"Found experience ID: {experience_id}")
            exp = Experience(self.session, experience_id)
            if self.get_option("email") and self.get_option("password"):
                if exp.login(self.get_option("email"),
                             self.get_option("password")):
                    log.info(
                        f"Logged in to Funimation as {self.get_option('email')}"
                    )
                else:
                    log.warning("Failed to login")

            if exp.episode_info:
                log.debug(f"Found episode: {exp.episode_info['episodeTitle']}")
                log.debug(
                    f"  has languages: {', '.join(exp.episode_info['languages'].keys())}"
                )
                log.debug(f"  requested language: {rlanguage}")
                log.debug(f"  current language:   {exp.language}")
                if rlanguage != exp.language:
                    log.debug(f"switching language to: {rlanguage}")
                    exp.set_language(rlanguage)
                    if exp.language != rlanguage:
                        log.warning(
                            f"Requested language {rlanguage} is not available, continuing with {exp.language}"
                        )
                    else:
                        log.debug(f"New experience ID: {exp.experience_id}")

                subtitles = None
                stream_metadata = {}
                disposition = {}
                for subtitle in exp.subtitles():
                    log.debug(f"Subtitles: {subtitle['src']}")
                    if subtitle["src"].endswith(
                            ".vtt") or subtitle["src"].endswith(".srt"):
                        sub_lang = {
                            "en": "eng",
                            "ja": "jpn"
                        }[subtitle["language"]]
                        # pick the first suitable subtitle stream
                        subtitles = subtitles or HTTPStream(
                            self.session, subtitle["src"])
                        stream_metadata["s:s:0"] = [
                            "language={0}".format(sub_lang)
                        ]
                    stream_metadata["s:a:0"] = [
                        "language={0}".format(exp.language_code)
                    ]

                sources = exp.sources()
                if 'errors' in sources:
                    for error in sources['errors']:
                        log.error("{0} : {1}".format(error['title'],
                                                     error['detail']))
                    return

                for item in sources["items"]:
                    url = item["src"]
                    if ".m3u8" in url:
                        for q, s in HLSStream.parse_variant_playlist(
                                self.session, url).items():
                            if self.get_option("mux_subtitles") and subtitles:
                                yield q, MuxedStream(self.session,
                                                     s,
                                                     subtitles,
                                                     metadata=stream_metadata,
                                                     disposition=disposition)
                            else:
                                yield q, s
                    elif ".mp4" in url:
                        # TODO: fix quality
                        s = HTTPStream(self.session, url)
                        if self.get_option("mux_subtitles") and subtitles:
                            yield self.mp4_quality, MuxedStream(
                                self.session,
                                s,
                                subtitles,
                                metadata=stream_metadata,
                                disposition=disposition)
                        else:
                            yield self.mp4_quality, s

        else:
            log.error("Could not find experience ID?!")
Ejemplo n.º 6
0
    def _get_streams(self):
        data = None

        m = self._re_url.match(self.url).groupdict()
        if m['slug_live']:
            res = self.session.http.get('https://api.pluto.tv/v2/channels')
            data = self.session.http.json(res,
                                          schema=self._schema_media(
                                              m['slug_live']))
        elif m['slug_series'] and m['slug_episode']:
            res = self.session.http.get(
                f'http://api.pluto.tv/v3/vod/slugs/{m["slug_series"]}')
            data = self.session.http.json(
                res,
                schema=validate.Schema(
                    {
                        'seasons':
                        validate.all([{
                            'episodes':
                            self._schema_media(m['slug_episode'])
                        }], validate.filter(
                            lambda k: k['episodes'] is not None))
                    }, validate.get('seasons'), validate.get(0),
                    validate.any(None, validate.get('episodes'))),
            )
        elif m['slug_movies']:
            res = self.session.http.get(
                'https://api.pluto.tv/v3/vod/categories',
                params={
                    'includeItems': 'true',
                    'deviceType': 'web'
                })
            data = self.session.http.json(
                res,
                schema=validate.Schema(
                    {
                        'categories':
                        validate.all([{
                            'items':
                            self._schema_media(m['slug_movies'])
                        }], validate.filter(lambda k: k['items'] is not None))
                    },
                    validate.get('categories'),
                    validate.get(0),
                    validate.any(None, validate.get('items')),
                ),
            )

        log.trace(f'{data!r}')
        if data is None or not data.get('stitched'):
            return

        self.title = data['name']
        stream_url_no_sid = data['stitched']['urls'][0]['url']
        device_id = str(uuid4())
        stream_url = update_qsd(
            stream_url_no_sid, {
                'deviceId': device_id,
                'sid': device_id,
                'deviceType': 'web',
                'deviceMake': 'Firefox',
                'deviceModel': 'Firefox',
                'appName': 'web',
            })

        self.session.set_option('ffmpeg-fout', 'mpegts')
        for q, s in HLSStream.parse_variant_playlist(self.session,
                                                     stream_url).items():
            yield q, MuxedStream(self.session, s)
Ejemplo n.º 7
0
    def _get_streams(self):
        info = self._get_stream_info(self.url)
        if not info:
            return

        formats = info.get("fmt_list")
        streams = {}
        protected = False
        for stream_info in info.get("url_encoded_fmt_stream_map", []):
            if stream_info.get("s"):
                protected = True
                continue

            stream = HTTPStream(self.session, stream_info["url"])
            name = formats.get(stream_info["itag"]) or stream_info["quality"]

            if stream_info.get("stereo3d"):
                name += "_3d"

            streams[name] = stream

        adaptive_streams = {}
        best_audio_itag = None

        # Extract audio streams from the DASH format list
        for stream_info in info.get("adaptive_fmts", []):
            if stream_info.get("s"):
                protected = True
                continue

            stream_params = dict(parse_qsl(stream_info["url"]))
            if "itag" not in stream_params:
                continue
            itag = int(stream_params["itag"])
            # extract any high quality streams only available in adaptive formats
            adaptive_streams[itag] = stream_info["url"]

            stream_type, stream_format = stream_info["type"]
            if stream_type == "audio":
                stream = HTTPStream(self.session, stream_info["url"])
                name = "audio_{0}".format(stream_format)
                streams[name] = stream

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[
                        itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(
                self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in self.adp_video.items():
                if itag in adaptive_streams:
                    vurl = adaptive_streams[itag]
                    streams[name] = MuxedStream(self.session,
                                                HTTPStream(self.session, vurl),
                                                HTTPStream(self.session, aurl))

        hls_playlist = info.get("hlsvp")
        if hls_playlist:
            try:
                hls_streams = HLSStream.parse_variant_playlist(
                    self.session,
                    hls_playlist,
                    headers=HLS_HEADERS,
                    namekey="pixels")
                streams.update(hls_streams)
            except IOError as err:
                self.logger.warning("Failed to extract HLS streams: {0}", err)

        if not streams and protected:
            raise PluginError("This plugin does not support protected videos, "
                              "try youtube-dl instead")

        return streams
Ejemplo n.º 8
0
    def _get_streams(self):
        info = self._get_stream_info(self.url)
        if not info:
            return

        formats = info.get("fmt_list")
        streams = {}
        protected = False
        for stream_info in info.get("url_encoded_fmt_stream_map", []):
            if stream_info.get("s"):
                protected = True
                continue

            stream = HTTPStream(self.session, stream_info["url"])
            name = formats.get(stream_info["itag"]) or stream_info["quality"]

            if stream_info.get("stereo3d"):
                name += "_3d"

            streams[name] = stream

        adaptive_streams = {}
        best_audio_itag = None

        # Extract audio streams from the DASH format list
        for stream_info in info.get("adaptive_fmts", []):
            if stream_info.get("s"):
                protected = True
                continue

            stream_params = dict(parse_qsl(stream_info["url"]))
            if "itag" not in stream_params:
                continue
            itag = int(stream_params["itag"])
            # extract any high quality streams only available in adaptive formats
            adaptive_streams[itag] = stream_info["url"]

            stream_type, stream_format = stream_info["type"]
            if stream_type == "audio":
                stream = HTTPStream(self.session, stream_info["url"])
                name = "audio_{0}".format(stream_format)
                streams[name] = stream

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in self.adp_video.items():
                if itag in adaptive_streams:
                    vurl = adaptive_streams[itag]
                    streams[name] = MuxedStream(self.session,
                                                HTTPStream(self.session, vurl),
                                                HTTPStream(self.session, aurl))

        hls_playlist = info.get("hlsvp")
        if hls_playlist:
            try:
                hls_streams = HLSStream.parse_variant_playlist(
                    self.session, hls_playlist, headers=HLS_HEADERS, namekey="pixels"
                )
                streams.update(hls_streams)
            except IOError as err:
                self.logger.warning("Failed to extract HLS streams: {0}", err)

        if not streams and protected:
            raise PluginError("This plugin does not support protected videos, "
                              "try youtube-dl instead")

        return streams
Ejemplo n.º 9
0
    def _create_adaptive_streams(self, info, streams):
        if not MuxedStream.is_usable(self.session):
            log.info("Cannot use FFMPEG")
            return streams

        adaptive_streams = {}
        best_audio_itag = None
        adp_video = self.adp_video_h264.copy()
        vp9 = "vp9" if hostname() in self.stb_vp9_1 or hostname(
        ) in self.stb_vp9_2 else ""
        if not vp9:
            log.debug("STB w/o vp9 4K support detected")
            if self.get_option("yes-vp9-codecs"):
                vp9 = "vp9"
        elif self.get_option("no-vp9-codecs"):
            vp9 = ""
            log.info("VP9 Codecs are skipped")
        if vp9:
            adp_video.update(self.adp_video_vp9)
            if self.get_option(
                    "yes-vp9-hdr-codecs") or hostname() in self.stb_vp9_2:
                adp_video.update(self.adp_video_vp9_hdr)

        # Extract streams from the DASH format list
        for stream_info in info.get("formats", []):
            itag = int(stream_info["format_id"])
            if itag not in self.adp_audio and itag not in adp_video:
                log.debug(
                    "Skipped format:{}, Codec:{}",
                    stream_info["format"],
                    stream_info["acodec"] if stream_info["acodec"] != "none"
                    else stream_info["vcodec"],
                )
                continue

            # extract any high quality streams only available in adaptive formats and not skipped
            adaptive_streams[itag] = stream_info["url"]
            stream_format = stream_info["ext"]
            if itag in self.adp_audio:
                if self.get_option(
                        "no-opus-codec") and stream_info["acodec"] == "opus":
                    log.debug("Skipped format:{}, Codec:{}",
                              stream_info["format"], stream_info["acodec"])
                    continue

                stream = HTTPStream(self.session, stream_info["url"])
                name = "audio_{0}".format(stream_format)
                streams[name] = stream

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[
                        itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(
                self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in adp_video.items():
                if itag in adaptive_streams:
                    vurl = adaptive_streams[itag]
                    log.debug(
                        "MuxedStream: v {video} a {audio} = {name}".format(
                            audio=best_audio_itag,
                            name=name,
                            video=itag,
                        ))
                    streams[name] = MuxedStream(self.session,
                                                HTTPStream(self.session, vurl),
                                                HTTPStream(self.session, aurl))

        return streams
Ejemplo n.º 10
0
    def _get_streams(self):
        http.headers = {"User-Agent": useragents.CHROME}
        res = http.get(self.url)

        rlanguage = self.get_option("language")

        id_m = self.experience_id_re.search(res.text)
        experience_id = id_m and int(id_m.group(1))
        if experience_id:
            self.logger.debug("Found experience ID: {0}", experience_id)
            exp = Experience(experience_id)

            self.logger.debug("Found episode: {0}",
                              exp.episode_info["episodeTitle"])
            self.logger.debug("  has languages: {0}",
                              ", ".join(exp.episode_info["languages"].keys()))
            self.logger.debug("  requested language: {0}", rlanguage)
            self.logger.debug("  current language:   {0}", exp.language)
            if rlanguage != exp.language:
                self.logger.debug("switching language to: {0}", rlanguage)
                exp.set_language(rlanguage)
                if exp.language != rlanguage:
                    self.logger.warning(
                        "Requested language {0} is not available, continuing with {1}",
                        rlanguage, exp.language)
                else:
                    self.logger.debug("New experience ID: {0}",
                                      exp.experience_id)

            subtitles = None
            stream_metadata = {}
            disposition = {}
            for subtitle in exp.subtitles():
                self.logger.info("Subtitles: {0}", subtitle["src"])
                if subtitle["src"].endswith(
                        ".vtt") or subtitle["src"].endswith(".srt"):
                    sub_lang = {"en": "eng", "ja": "jpn"}[subtitle["language"]]
                    # pick the first suitable subtitle stream
                    subtitles = subtitles or HTTPStream(
                        self.session, subtitle["src"])
                    stream_metadata["s:s:0"] = [
                        "language={0}".format(sub_lang)
                    ]
                stream_metadata["s:a:0"] = [
                    "language={0}".format(exp.language_code)
                ]

            for item in exp.sources()["items"]:
                url = item["src"]
                if ".m3u8" in url:
                    for q, s in HLSStream.parse_variant_playlist(
                            self.session, url).items():
                        if self.get_option("mux_subtitles") and subtitles:
                            yield q, MuxedStream(self.session,
                                                 s,
                                                 subtitles,
                                                 metadata=stream_metadata,
                                                 disposition=disposition)
                        else:
                            yield q, s
                elif ".mp4" in url:
                    # TODO: fix quality
                    s = HTTPStream(self.session, url)
                    if self.get_option("mux_subtitles") and subtitles:
                        yield self.mp4_quality, MuxedStream(
                            self.session,
                            s,
                            subtitles,
                            metadata=stream_metadata,
                            disposition=disposition)
                    else:
                        yield self.mp4_quality, s

        else:
            self.logger.error("Could not find experience ID?!")
Ejemplo n.º 11
0
    def _get_streams(self):
        page = http.get(self.url, schema=_schema)
        if not page:
            return

        pubkey_pem = get_public_key(self.cache,
                                    urljoin(self.url, page["clientlibs"]))
        if not pubkey_pem:
            raise PluginError("Unable to get public key")

        flashvars = page["flashvars"]

        params = {"cashPath": int(time.time() * 1000)}
        res = http.get(urljoin(self.url, flashvars["country"]), params=params)
        if not res:
            return
        language = http.xml(res, schema=_language_schema)

        api_params = {}
        for key in ("ss_id", "mv_id", "device_cd", "ss1_prm", "ss2_prm",
                    "ss3_prm"):
            if flashvars.get(key, ""):
                api_params[key] = flashvars[key]

        aeskey = number.long_to_bytes(random.getrandbits(8 * 32), 32)

        params = {
            "s": flashvars["s"],
            "c": language,
            "e": self.url,
            "d": aes_encrypt(aeskey, json.dumps(api_params)),
            "a": rsa_encrypt(pubkey_pem, aeskey)
        }
        res = http.get(urljoin(self.url, flashvars["init"]), params=params)
        if not res:
            return
        rtn = http.json(res, schema=_init_schema)
        if not rtn:
            return

        init_data = parse_json(aes_decrypt(aeskey, rtn))

        parsed = urlparse(init_data["play_url"])
        if parsed.scheme != "https" or not parsed.path.startswith(
                "/i/") or not parsed.path.endswith("/master.m3u8"):
            return
        hlsstream_url = init_data["play_url"]

        streams = HLSStream.parse_variant_playlist(self.session, hlsstream_url)

        if "caption_url" in init_data:
            if self.get_option("mux_subtitles") and FFMPEGMuxer.is_usable(
                    self.session):
                res = http.get(init_data["caption_url"])
                srt = http.xml(res, ignore_ns=True, schema=_xml_to_srt_schema)
                subfiles = []
                metadata = {}
                for i, lang, srt in ((i, s[0], s[1])
                                     for i, s in enumerate(srt)):
                    subfile = tempfile.TemporaryFile()
                    subfile.write(srt.encode("utf8"))
                    subfile.seek(0)
                    subfiles.append(FileStream(self.session, fileobj=subfile))
                    metadata["s:s:{0}".format(i)] = [
                        "language={0}".format(lang)
                    ]

                for n, s in streams.items():
                    yield n, MuxedStream(self.session,
                                         s,
                                         *subfiles,
                                         maps=list(range(0,
                                                         len(metadata) + 1)),
                                         metadata=metadata)
                return
            else:
                self.logger.info("Subtitles: {0}".format(
                    init_data["caption_url"]))

        for s in streams.items():
            yield s
Ejemplo n.º 12
0
    def _get_streams(self):
        self.id = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.transform(
                    re.compile(r"\bdata-setup='({.+?})'", re.DOTALL).search),
                validate.any(
                    None,
                    validate.all(
                        validate.get(1), validate.parse_json(), {
                            "idAsset":
                            validate.any(
                                int, validate.all(str,
                                                  validate.transform(int))),
                        }, validate.get("idAsset"))),
            ))
        if not self.id:
            return

        urls = self.session.http.get(
            self.URL_VIDEOS.format(id=self.id),
            schema=validate.Schema(
                validate.transform(ZTNR.translate),
                validate.transform(list),
                [(str, validate.url())],
            ),
        )

        url = next(
            (url for _, url in urls if urlparse(url).path.endswith(".m3u8")),
            None)
        if not url:
            url = next(
                (url
                 for _, url in urls if urlparse(url).path.endswith(".mp4")),
                None)
            if url:
                yield "vod", HTTPStream(self.session, url)
            return

        streams = HLSStream.parse_variant_playlist(self.session, url).items()

        if self.options.get("mux-subtitles"):
            subs = self.session.http.get(
                self.URL_SUBTITLES.format(id=self.id),
                schema=validate.Schema(
                    validate.parse_json(),
                    {
                        "page": {
                            "items": [{
                                "lang": str,
                                "src": validate.url(),
                            }]
                        }
                    },
                    validate.get(("page", "items")),
                ),
            )
            if subs:
                subtitles = {
                    s["lang"]:
                    HTTPStream(self.session,
                               update_scheme("https://", s["src"], force=True))
                    for s in subs
                }
                for quality, stream in streams:
                    yield quality, MuxedStream(self.session,
                                               stream,
                                               subtitles=subtitles)
                return

        yield from streams
Ejemplo n.º 13
0
    def _get_streams(self):
        http.headers = {"User-Agent": useragents.CHROME}
        res = http.get(self.url)

        # remap en to english, and ja to japanese
        rlanguage = {
            "en": "english",
            "ja": "japanese"
        }.get(
            self.get_option("language").lower(),
            self.get_option("language").lower())
        if "_Incapsula_Resource" in res.text:
            self.bypass_incapsula(res)
            res = http.get(self.url)

        id_m = self.experience_id_re.search(res.text)
        experience_id = id_m and int(id_m.group(1))
        if experience_id:
            log.debug("Found experience ID: {0}", experience_id)
            exp = Experience(experience_id)
            if self.get_option("email") and self.get_option("password"):
                if exp.login(self.get_option("email"),
                             self.get_option("password")):
                    log.info("Logged in to Funimation as {0}",
                             self.get_option("email"))
                else:
                    log.warning("Failed to login")

            log.debug("Found episode: {0}", exp.episode_info["episodeTitle"])
            log.debug("  has languages: {0}",
                      ", ".join(exp.episode_info["languages"].keys()))
            log.debug("  requested language: {0}", rlanguage)
            log.debug("  current language:   {0}", exp.language)
            if rlanguage != exp.language:
                log.debug("switching language to: {0}", rlanguage)
                exp.set_language(rlanguage)
                if exp.language != rlanguage:
                    log.warning(
                        "Requested language {0} is not available, continuing with {1}",
                        rlanguage, exp.language)
                else:
                    log.debug("New experience ID: {0}", exp.experience_id)

            subtitles = None
            stream_metadata = {}
            disposition = {}
            for subtitle in exp.subtitles():
                log.debug("Subtitles: {0}", subtitle["src"])
                if subtitle["src"].endswith(
                        ".vtt") or subtitle["src"].endswith(".srt"):
                    sub_lang = {"en": "eng", "ja": "jpn"}[subtitle["language"]]
                    # pick the first suitable subtitle stream
                    subtitles = subtitles or HTTPStream(
                        self.session, subtitle["src"])
                    stream_metadata["s:s:0"] = [
                        "language={0}".format(sub_lang)
                    ]
                stream_metadata["s:a:0"] = [
                    "language={0}".format(exp.language_code)
                ]

            sources = exp.sources()
            if 'errors' in sources:
                for error in sources['errors']:
                    log.error("{0} : {1}".format(error['title'],
                                                 error['detail']))
                return

            for item in sources["items"]:
                url = item["src"]
                if ".m3u8" in url:
                    for q, s in HLSStream.parse_variant_playlist(
                            self.session, url).items():
                        if self.get_option("mux_subtitles") and subtitles:
                            yield q, MuxedStream(self.session,
                                                 s,
                                                 subtitles,
                                                 metadata=stream_metadata,
                                                 disposition=disposition)
                        else:
                            yield q, s
                elif ".mp4" in url:
                    # TODO: fix quality
                    s = HTTPStream(self.session, url)
                    if self.get_option("mux_subtitles") and subtitles:
                        yield self.mp4_quality, MuxedStream(
                            self.session,
                            s,
                            subtitles,
                            metadata=stream_metadata,
                            disposition=disposition)
                    else:
                        yield self.mp4_quality, s

        else:
            log.error("Could not find experience ID?!")