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)} "
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} "