Example #1
0
    def __get_ffmpeg_input_clause(self, ytdl_video_format):
        video_url_type = self.__get_video_url_type()
        if video_url_type == self.__VIDEO_URL_TYPE_YOUTUBE:
            """
            Pipe to mbuffer to avoid video drop outs when youtube-dl temporarily loses its connection
            and is trying to reconnect:

                [download] Got server HTTP error: [Errno 104] Connection reset by peer. Retrying (attempt 1 of 10)...
                [download] Got server HTTP error: [Errno 104] Connection reset by peer. Retrying (attempt 2 of 10)...
                [download] Got server HTTP error: [Errno 104] Connection reset by peer. Retrying (attempt 3 of 10)...

            This can happen from time to time when downloading long videos.
            Youtube-dl should download quickly until it fills the mbuffer. After the mbuffer is filled,
            ffmpeg will apply backpressure to youtube-dl because of ffmpeg's `-re` flag

            --retries infinite: using this to avoid scenarios where all of the retries (10 by default) were
            exhausted on long video downloads. After a while, retries would be necessary to reconnect. The
            retries would be successful, but the connection errors would happen again a few minutes later.
            This allows us to keep retrying whenever it is necessary.

            Use yt-dlp, a fork of youtube-dl that has a workaround (for now) for an issue where youtube has been
            throttling youtube-dl’s download speed:
            https://github.com/ytdl-org/youtube-dl/issues/29326#issuecomment-879256177
            """
            youtube_dl_cmd_template = (
                "yt-dlp {0} --retries infinite --format {1} --output - {2} | "
                + "mbuffer -q -Q -m {3}b")

            log_opts = '--no-progress'
            if Logger.get_level() <= Logger.DEBUG:
                log_opts = ''  # show video download progress
            if not sys.stderr.isatty():
                log_opts += ' --newline'

            if not ytdl_video_format:
                ytdl_video_format = self.__config_loader.get_youtube_dl_video_format(
                )

            # 50 MB. Based on one video, 1080p avc1 video consumes about 0.36 MB/s. So this should
            # be enough buffer for ~139s
            video_buffer_size = 1024 * 1024 * 50
            youtube_dl_video_cmd = youtube_dl_cmd_template.format(
                shlex.quote(self.__video_url), shlex.quote(ytdl_video_format),
                log_opts, video_buffer_size)

            # 5 MB. Based on one video, audio consumes about 0.016 MB/s. So this should
            # be enough buffer for ~312s
            audio_buffer_size = 1024 * 1024 * 5
            youtube_dl_audio_cmd = youtube_dl_cmd_template.format(
                shlex.quote(self.__video_url),
                shlex.quote(self.__AUDIO_FORMAT), log_opts, audio_buffer_size)

            return f"-i <({youtube_dl_video_cmd}) -i <({youtube_dl_audio_cmd})"
        elif video_url_type == self.__VIDEO_URL_TYPE_LOCAL_FILE:
            return f"-i {shlex.quote(self.__video_url)} "
Example #2
0
    def __get_standard_ffmpeg_cmd(self):
        # unfortunately there's no way to make ffmpeg output its stats progress stuff with line breaks
        log_opts = '-nostats '
        if sys.stderr.isatty():
            log_opts = '-stats '

        if Logger.get_level() <= Logger.DEBUG:
            pass  # don't change anything, ffmpeg is pretty verbose by default
        else:
            log_opts += '-loglevel error'

        # Note: don't use ffmpeg's `-xerror` flag:
        # https://gist.github.com/dasl-/1ad012f55f33f14b44393960f66c6b00
        return f"ffmpeg -hide_banner {log_opts} "