示例#1
0
    def re_encode(self, input_path, target_path, target_encoding=None,
                  encoder=EncoderFFmpeg(must_exist=False), show_progress=True):
        stream = self.metadata["streams"].getbest()
        total_chunks = self.calculate_total_chunks(stream["filesize"])
        process = encoder.re_encode_from_stdin(
            stream["encoding"],
            target_path,
            target_encoding=target_encoding
        )
        with open(input_path, "rb") as fin:
            for _ in tqdm.trange(total_chunks):
                chunk = fin.read(self._chunksize)
                process.stdin.write(chunk)

        process.stdin.close()
        process.wait()
示例#2
0
    def download_while_re_encoding(self, stream, target_path, target_encoding=None,
                                   encoder=EncoderFFmpeg(must_exist=False), show_progress=True):
        total_chunks = self.calculate_total_chunks(stream["filesize"])
        process = encoder.re_encode_from_stdin(
            stream["encoding"],
            target_path,
            target_encoding=target_encoding
        )
        response = stream["connection"]

        progress_bar = self.make_progress_bar(total_chunks)
        for _ in progress_bar:
            chunk = response.read(self._chunksize)
            process.stdin.write(chunk)

        process.stdin.close()
        process.wait()
示例#3
0
    def download_while_re_encoding(self,
                                   stream,
                                   target_path,
                                   target_encoding=None,
                                   encoder=EncoderFFmpeg(must_exist=False),
                                   show_progress=True):
        """
        Downloads a stream while simuntaneously encoding it to a
        given target format.

        Parameters
        ----------
        stream: `dict`
            A `dict` containing stream information in the keys:
            `encoding`, `filesize`, `connection`.

        target_path: `str`
            Path to file to write the target stream to.

        target_encoding: `str`, `None`
            Specify a target encoding. If ``None``, the target encoding
            is automatically determined from the ``target_path``.

        encoder: :class:`spotdl.encode.EncoderBase` object
            A :class:`spotdl.encode.EncoderBase` object to use for encoding.

        show_progress: `bool`
            Whether or not to display a progress bar.
        """

        total_chunks = self._calculate_total_chunks(stream["filesize"])
        process = encoder.re_encode_from_stdin(stream["encoding"],
                                               target_path,
                                               target_encoding=target_encoding)
        response = stream["connection"]

        progress_bar = self._make_progress_bar(total_chunks)
        for _ in progress_bar:
            chunk = response.read(self._chunksize)
            process.stdin.write(chunk)

        process.stdin.close()
        process.wait()
示例#4
0
    def re_encode(self,
                  input_path,
                  target_path,
                  target_encoding=None,
                  encoder=EncoderFFmpeg(must_exist=False),
                  show_progress=True):
        """
        Encodes an already downloaded stream.

        Parameters
        ----------
        input_path: `str`
            Path to input file.

        target_path: `str`
            Path to target file.

        target_encoding: `str`
            Encoding to encode the input file to. If ``None``, the
            target encoding is determined from ``target_path``.

        encoder: :class:`spotdl.encode.EncoderBase` object
            A :class:`spotdl.encode.EncoderBase` object to use for encoding.

        show_progress: `bool`
            Whether or not to display a progress bar.
        """
        stream = self.metadata["streams"].getbest()
        total_chunks = self._calculate_total_chunks(stream["filesize"])
        process = encoder.re_encode_from_stdin(stream["encoding"],
                                               target_path,
                                               target_encoding=target_encoding)
        with open(input_path, "rb") as fin:
            for _ in tqdm.trange(total_chunks):
                chunk = fin.read(self._chunksize)
                process.stdin.write(chunk)

        process.stdin.close()
        process.wait()
示例#5
0
    def download_track_from_metadata(self, metadata):
        track = Track(metadata, cache_albumart=(not self.arguments["no_metadata"]))
        stream = metadata["streams"].get(
            quality=self.arguments["quality"],
            preftype=self.arguments["input_ext"],
        )
        if stream is None:
            logger.error('No matching streams found for given input format: "{}".'.format(
                self.arguments["input_ext"]
            ))
            return

        if self.arguments["no_encode"]:
            output_extension = stream["encoding"]
        else:
            output_extension = self.arguments["output_ext"]

        filename = spotdl.metadata.format_string(
            self.arguments["output_file"],
            metadata,
            output_extension=output_extension,
            sanitizer=lambda s: spotdl.util.sanitize(
                s, spaces_to_underscores=self.arguments["no_spaces"]
            )
        )
        download_to_stdout = filename == "-"
        temp_filename = self.generate_temp_filename(filename, for_stdout=download_to_stdout)

        to_skip_download = self.arguments["dry_run"]
        if os.path.isfile(filename):
            logger.info('A file with name "{filename}" already exists.'.format(
                filename=filename
            ))
            to_skip_download = to_skip_download \
                or not self.should_we_overwrite_existing_file(self.arguments["overwrite"])

        if to_skip_download:
            logger.debug("Skip track download.")
            return

        if not self.arguments["no_metadata"]:
            metadata["lyrics"].start()

        os.makedirs(os.path.dirname(filename) or ".", exist_ok=True)

        logger.info('Downloading to "{filename}"'.format(filename=filename))
        if self.arguments["no_encode"]:
            track.download(stream, temp_filename)
        else:
            encoder = EncoderFFmpeg()
            if self.arguments["trim_silence"]:
                encoder.set_trim_silence()
            track.download_while_re_encoding(
                stream,
                temp_filename,
                target_encoding=output_extension,
                encoder=encoder,
            )

        if not self.arguments["no_metadata"]:
            track.metadata["lyrics"] = track.metadata["lyrics"].join()
            self.apply_metadata(track, temp_filename, output_extension)

        if not download_to_stdout:
            logger.debug("Renaming {temp_filename} to {filename}.".format(
                temp_filename=temp_filename, filename=filename
            ))
            os.rename(temp_filename, filename)

        return filename
示例#6
0
 def test_generate_encode_command(self, files, expected_command):
     encoder = EncoderFFmpeg()
     assert encoder._generate_encode_command(*files) == expected_command
示例#7
0
 def test_generate_encode_command_and_trim_silence(self, files,
                                                   expected_command):
     encoder = EncoderFFmpeg()
     encoder.set_trim_silence()
     assert encoder._generate_encode_command(*files) == expected_command
示例#8
0
 def test_ffmpeg_not_found_error(self):
     with pytest.raises(FFmpegNotFoundError):
         EncoderFFmpeg(encoder_path="/a/nonexistent/path")
示例#9
0
 def test_generate_encode_command_with_debug(self, files, expected_command):
     encoder = EncoderFFmpeg()
     encoder.set_debuglog()
     assert encoder._generate_encode_command(*files) == expected_command