Exemple #1
0
    def descramble(self) -> None:
        """Descramble the stream data and build Stream instances.

        The initialization process takes advantage of Python's
        "call-by-reference evaluation," which allows dictionary transforms to
        be applied in-place, instead of holding references to mutations at each
        interstitial step.

        :rtype: None

        """
        logger.info("init started")

        self.vid_info = dict(parse_qsl(self.vid_info_raw))
        if self.age_restricted:
            self.player_config_args = self.vid_info
        else:
            assert self.watch_html is not None
            self.player_config_args = get_ytplayer_config(self.watch_html)["args"]

            # Fix for KeyError: 'title' issue #434
            if "title" not in self.player_config_args:  # type: ignore
                i_start = self.watch_html.lower().index("<title>") + len("<title>")
                i_end = self.watch_html.lower().index("</title>")
                title = self.watch_html[i_start:i_end].strip()
                index = title.lower().rfind(" - youtube")
                title = title[:index] if index > 0 else title
                self.player_config_args["title"] = unescape(title)

        # https://github.com/nficano/pytube/issues/165
        stream_maps = ["url_encoded_fmt_stream_map"]
        if "adaptive_fmts" in self.player_config_args:
            stream_maps.append("adaptive_fmts")

        # unscramble the progressive and adaptive stream manifests.
        for fmt in stream_maps:
            if not self.age_restricted and fmt in self.vid_info:
                apply_descrambler(self.vid_info, fmt)
            apply_descrambler(self.player_config_args, fmt)

            if not self.js:
                if not self.embed_html:
                    self.embed_html = request.get(url=self.embed_url)
                self.js_url = extract.js_url(self.embed_html)
                self.js = request.get(self.js_url)

            apply_signature(self.player_config_args, fmt, self.js)

            # build instances of :class:`Stream <Stream>`
            self.initialize_stream_objects(fmt)

        # load the player_response object (contains subtitle information)
        self.player_response = json.loads(self.player_config_args["player_response"])
        del self.player_config_args["player_response"]
        self.stream_monostate.title = self.title
        self.stream_monostate.duration = self.length

        logger.info("init finished successfully")
Exemple #2
0
    def descramble(self) -> None:
        """Descramble the stream data and build Stream instances.

        The initialization process takes advantage of Python's
        "call-by-reference evaluation," which allows dictionary transforms to
        be applied in-place, instead of holding references to mutations at each
        interstitial step.

        :rtype: None

        """
        self.vid_info = dict(parse_qsl(self.vid_info_raw))
        self.player_config_args = self.vid_info
        self.player_response = json.loads(self.vid_info['player_response'])

        # On pre-signed videos, we need to use get_ytplayer_config to fix
        #  the player_response item
        if 'streamingData' not in self.player_config_args['player_response']:
            config_response = get_ytplayer_config(self.watch_html)
            if 'args' in config_response:
                self.player_config_args['player_response'] = config_response['args']['player_response']  # noqa: E501
            else:
                self.player_config_args['player_response'] = config_response

        # https://github.com/nficano/pytube/issues/165
        stream_maps = ["url_encoded_fmt_stream_map"]
        if "adaptive_fmts" in self.player_config_args:
            stream_maps.append("adaptive_fmts")

        # unscramble the progressive and adaptive stream manifests.
        for fmt in stream_maps:
            if not self.age_restricted and fmt in self.vid_info:
                apply_descrambler(self.vid_info, fmt)
            apply_descrambler(self.player_config_args, fmt)

            if not self.js:
                if not self.embed_html:
                    self.embed_html = request.get(url=self.embed_url)
                self.js_url = extract.js_url(self.embed_html)
                self.js = request.get(self.js_url)

            apply_signature(self.player_config_args, fmt, self.js)

            # build instances of :class:`Stream <Stream>`
            self.initialize_stream_objects(fmt)

        # load the player_response object (contains subtitle information)
        if isinstance(self.player_config_args["player_response"], str):
            self.player_response = json.loads(
                self.player_config_args["player_response"]
            )
        else:
            self.player_response = self.player_config_args["player_response"]
        del self.player_config_args["player_response"]
        self.stream_monostate.title = self.title
        self.stream_monostate.duration = self.length
Exemple #3
0
    def fmt_streams(self):
        """Returns a list of streams if they have been initialized.

        If the streams have not been initialized, finds all relevant
        streams and initializes them.
        """
        self.check_availability()
        if self._fmt_streams:
            return self._fmt_streams

        self._fmt_streams = []
        # https://github.com/pytube/pytube/issues/165
        stream_maps = ["url_encoded_fmt_stream_map"]
        if "adaptive_fmts" in self.player_config_args:
            stream_maps.append("adaptive_fmts")

        # unscramble the progressive and adaptive stream manifests.
        for fmt in stream_maps:
            if not self.age_restricted and fmt in self.vid_info:
                extract.apply_descrambler(self.vid_info, fmt)
            extract.apply_descrambler(self.player_config_args, fmt)

            # If the cached js doesn't work, try fetching a new js file
            # https://github.com/pytube/pytube/issues/1054
            try:
                extract.apply_signature(self.player_config_args, fmt, self.js)
            except exceptions.ExtractError:
                # To force an update to the js file, we clear the cache and retry
                self._js = None
                self._js_url = None
                pytube.__js__ = None
                pytube.__js_url__ = None
                extract.apply_signature(self.player_config_args, fmt, self.js)

            # build instances of :class:`Stream <Stream>`
            # Initialize stream objects
            stream_manifest = self.player_config_args[fmt]
            for stream in stream_manifest:
                video = Stream(
                    stream=stream,
                    player_config_args=self.player_config_args,
                    monostate=self.stream_monostate,
                )
                self._fmt_streams.append(video)

        self.stream_monostate.title = self.title
        self.stream_monostate.duration = self.length

        return self._fmt_streams
Exemple #4
0
 def _decipher(self, retry: bool = False):
     if not pytube.__js__ or retry:
         self._getJS()
     try:
         '''
         These two are the main methods being used from PyTube.
         Used to decipher the stream URLs using player JavaScript & the player_response passed from the getStream method of this derieved class.
         These methods operate on the value of "player_response" key in dictionary of self._player_response & save _deciphered information in the "url_encoded_fmt_stream_map" key.
         '''
         apply_descrambler(self._player_response, "url_encoded_fmt_stream_map")
         apply_signature(
             self._player_response, "url_encoded_fmt_stream_map", pytube.__js__
         )
     except:
         '''
         Fetch updated player JavaScript to get new cipher algorithm.
         '''
         self._decipher(retry = False)
Exemple #5
0
    async def fmt_streams(self):
        """Returns a list of streams if they have been initialized.

        If the streams have not been initialized, finds all relevant
        streams and initializes them.
        """
        await self.check_availability()
        if self._fmt_streams:
            return self._fmt_streams

        self._fmt_streams = []
        # https://github.com/pytube/pytube/issues/165
        stream_maps = ["url_encoded_fmt_stream_map"]
        if "adaptive_fmts" in (await self.player_config_args):
            stream_maps.append("adaptive_fmts")

        # unscramble the progressive and adaptive stream manifests.
        for fmt in stream_maps:
            if not (await self.age_restricted) and fmt in (await
                                                           self.vid_info):
                apply_descrambler((await self.vid_info), fmt)
            apply_descrambler((await self.player_config_args), fmt)

            apply_signature((await self.player_config_args), fmt,
                            (await self.js))

            # build instances of :class:`Stream <Stream>`
            # Initialize stream objects
            stream_manifest = (await self.player_config_args)[fmt]
            for stream in stream_manifest:
                video = Stream(
                    stream=stream,
                    player_config_args=(await self.player_config_args),
                    monostate=self.stream_monostate,
                    session=self._client_session,
                )
                self._fmt_streams.append(video)

        self.stream_monostate.title = await self.title
        self.stream_monostate.duration = await self.length

        return self._fmt_streams
Exemple #6
0
    def fmt_streams(self):
        """Returns a list of streams if they have been initialized.

        If the streams have not been initialized, finds all relevant
        streams and initializes them.
        """
        self.check_availability()
        if self._fmt_streams:
            return self._fmt_streams

        self._fmt_streams = []

        stream_manifest = extract.apply_descrambler(self.streaming_data)

        # If the cached js doesn't work, try fetching a new js file
        # https://github.com/pytube/pytube/issues/1054
        try:
            extract.apply_signature(stream_manifest, self.vid_info, self.js)
        except exceptions.ExtractError:
            # To force an update to the js file, we clear the cache and retry
            self._js = None
            self._js_url = None
            pytube.__js__ = None
            pytube.__js_url__ = None
            extract.apply_signature(stream_manifest, self.vid_info, self.js)

        # build instances of :class:`Stream <Stream>`
        # Initialize stream objects
        for stream in stream_manifest:
            video = Stream(
                stream=stream,
                monostate=self.stream_monostate,
            )
            self._fmt_streams.append(video)

        self.stream_monostate.title = self.title
        self.stream_monostate.duration = self.length

        return self._fmt_streams
Exemple #7
0
def test_signature_cipher_does_not_error(stream_dict):
    config_args = extract.get_ytplayer_config(stream_dict)['args']
    extract.apply_descrambler(config_args, "url_encoded_fmt_stream_map")
    assert "s" in config_args["url_encoded_fmt_stream_map"][0].keys()
Exemple #8
0
def test_signature_cipher_does_not_error(stream_dict):
    extract.apply_descrambler(stream_dict, "url_encoded_fmt_stream_map")
    assert "s" in stream_dict["url_encoded_fmt_stream_map"][0].keys()