From c574be85f10de80482fa22a05d0b95bcc53a867c Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 23 Apr 2024 10:22:36 -0700 Subject: [PATCH 01/17] Refactored MoveFilesPP to respect non-video files --- yt_dlp/YoutubeDL.py | 55 ++++++++--- yt_dlp/postprocessor/ffmpeg.py | 25 +++-- .../postprocessor/movefilesafterdownload.py | 93 +++++++++++++------ 3 files changed, 125 insertions(+), 48 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 9f730d0384..5f652c6379 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -3236,13 +3236,15 @@ class YoutubeDL: sub_files = self._write_subtitles(info_dict, temp_filename) if sub_files is None: return - files_to_move.update(dict(sub_files)) + + files_to_move['requested_subtitles'] = sub_files thumb_files = self._write_thumbnails( 'video', info_dict, temp_filename, self.prepare_filename(info_dict, 'thumbnail')) if thumb_files is None: return - files_to_move.update(dict(thumb_files)) + + files_to_move['thumbnails'] = thumb_files infofn = self.prepare_filename(info_dict, 'infojson') _infojson_written = self._write_info_json('video', info_dict, infofn) @@ -3452,7 +3454,6 @@ class YoutubeDL: dl_filename = dl_filename or temp_filename info_dict['__finaldir'] = os.path.dirname(os.path.abspath(encodeFilename(full_filename))) - except network_exceptions as err: self.report_error('unable to download video data: %s' % error_to_compat_str(err)) return @@ -3644,8 +3645,6 @@ class YoutubeDL: os.remove(filename) except OSError: self.report_warning(f'Unable to delete file {filename}') - if filename in info.get('__files_to_move', []): # NB: Delete even if None - del info['__files_to_move'][filename] @staticmethod def post_extract(info_dict): @@ -3675,10 +3674,7 @@ class YoutubeDL: if not files_to_delete: return infodict - if self.params.get('keepvideo', False): - for f in files_to_delete: - infodict['__files_to_move'].setdefault(f, '') - else: + if not self.params.get('keepvideo', False): self._delete_downloaded_files( *files_to_delete, info=infodict, msg='Deleting original file %s (pass -k to keep)') return infodict @@ -4294,10 +4290,17 @@ class YoutubeDL: sub_filename = subtitles_filename(filename, sub_lang, sub_format, info_dict.get('ext')) sub_filename_final = subtitles_filename(sub_filename_base, sub_lang, sub_format, info_dict.get('ext')) existing_sub = self.existing_file((sub_filename_final, sub_filename)) + if existing_sub: self.to_screen(f'[info] Video subtitle {sub_lang}.{sub_format} is already present') sub_info['filepath'] = existing_sub - ret.append((existing_sub, sub_filename_final)) + ret.append({ + 'current_filepath': existing_sub, + 'final_filepath': sub_filename_final, + 'lang': sub_lang, + 'ext': sub_info['ext'] + }) + continue self.to_screen(f'[info] Writing video subtitles to: {sub_filename}') @@ -4308,7 +4311,13 @@ class YoutubeDL: with open(sub_filename, 'w', encoding='utf-8', newline='') as subfile: subfile.write(sub_info['data']) sub_info['filepath'] = sub_filename - ret.append((sub_filename, sub_filename_final)) + ret.append({ + 'current_filepath': sub_filename, + 'final_filepath': sub_filename_final, + 'lang': sub_lang, + 'ext': sub_info['ext'] + }) + continue except OSError: self.report_error(f'Cannot write video subtitles file {sub_filename}') @@ -4319,7 +4328,13 @@ class YoutubeDL: sub_copy.setdefault('http_headers', info_dict.get('http_headers')) self.dl(sub_filename, sub_copy, subtitle=True) sub_info['filepath'] = sub_filename - ret.append((sub_filename, sub_filename_final)) + ret.append({ + 'current_filepath': sub_filename, + 'final_filepath': sub_filename_final, + 'lang': sub_lang, + 'ext': sub_info['ext'] + }) + except (DownloadError, ExtractorError, IOError, OSError, ValueError) + network_exceptions as err: msg = f'Unable to download video subtitles for {sub_lang!r}: {err}' if self.params.get('ignoreerrors') is not True: # False or 'only_download' @@ -4360,7 +4375,12 @@ class YoutubeDL: self.to_screen('[info] %s is already present' % ( thumb_display_id if multiple else f'{label} thumbnail').capitalize()) t['filepath'] = existing_thumb - ret.append((existing_thumb, thumb_filename_final)) + ret.append({ + 'current_filepath': existing_thumb, + 'final_filepath': thumb_filename_final, + 'id': t['id'] + }) + else: self.to_screen(f'[info] Downloading {thumb_display_id} ...') try: @@ -4368,7 +4388,13 @@ class YoutubeDL: self.to_screen(f'[info] Writing {thumb_display_id} to: {thumb_filename}') with open(encodeFilename(thumb_filename), 'wb') as thumbf: shutil.copyfileobj(uf, thumbf) - ret.append((thumb_filename, thumb_filename_final)) + + ret.append({ + 'current_filepath': thumb_filename, + 'final_filepath': thumb_filename_final, + 'id': t['id'] + }) + t['filepath'] = thumb_filename except network_exceptions as err: if isinstance(err, HTTPError) and err.status == 404: @@ -4378,4 +4404,5 @@ class YoutubeDL: thumbnails.pop(idx) if ret and not write_all: break + return ret diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 7d7f3f0eb2..e794c1358d 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -1016,8 +1016,10 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor): 'filepath': new_file, } - info['__files_to_move'][new_file] = replace_extension( - info['__files_to_move'][sub['filepath']], new_ext) + for sub_info in info['__files_to_move']['requested_subtitles']: + if sub_info['lang'] == lang and sub_info['ext'] == sub['ext']: + sub_info['current_filepath'] = replace_extension(sub_info['current_filepath'], new_ext) + sub_info['final_filepath'] = replace_extension(sub_info['final_filepath'], new_ext) return sub_filenames, info @@ -1083,16 +1085,20 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): return imghdr.what(path) == 'webp' def fixup_webp(self, info, idx=-1): - thumbnail_filename = info['thumbnails'][idx]['filepath'] + thumbnail = info['thumbnails'][idx] + thumbnail_filename = thumbnail['filepath'] _, thumbnail_ext = os.path.splitext(thumbnail_filename) if thumbnail_ext: if thumbnail_ext.lower() != '.webp' and imghdr.what(thumbnail_filename) == 'webp': self.to_screen('Correcting thumbnail "%s" extension to webp' % thumbnail_filename) webp_filename = replace_extension(thumbnail_filename, 'webp') os.replace(thumbnail_filename, webp_filename) - info['thumbnails'][idx]['filepath'] = webp_filename - info['__files_to_move'][webp_filename] = replace_extension( - info['__files_to_move'].pop(thumbnail_filename), 'webp') + thumbnail['filepath'] = webp_filename + + for thumb_info in info['__files_to_move']['thumbnails']: + if thumb_info['id'] == thumbnail['id']: + thumb_info['current_filepath'] = replace_extension(thumbnail_filename, 'webp') + thumb_info['final_filepath'] = replace_extension(thumb_info['final_filepath'], 'webp') @staticmethod def _options(target_ext): @@ -1130,8 +1136,11 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): continue thumbnail_dict['filepath'] = self.convert_thumbnail(original_thumbnail, target_ext) files_to_delete.append(original_thumbnail) - info['__files_to_move'][thumbnail_dict['filepath']] = replace_extension( - info['__files_to_move'][original_thumbnail], target_ext) + + for thumb_info in info['__files_to_move']['thumbnails']: + if thumb_info['id'] == thumbnail_dict['id']: + thumb_info['current_filepath'] = replace_extension(thumb_info['current_filepath'], target_ext) + thumb_info['final_filepath'] = replace_extension(thumb_info['final_filepath'], target_ext) if not has_thumbnail: self.to_screen('There aren\'t any thumbnails to convert') diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index 23b09248c2..d990eedf6e 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -4,13 +4,11 @@ from .common import PostProcessor from ..compat import shutil from ..utils import ( PostProcessingError, - decodeFilename, - encodeFilename, make_dir, ) - class MoveFilesAfterDownloadPP(PostProcessor): + FILETYPE_KEYS = ['media', 'thumbnails', 'requested_subtitles'] def __init__(self, downloader=None, downloaded=True): PostProcessor.__init__(self, downloader) @@ -20,34 +18,77 @@ class MoveFilesAfterDownloadPP(PostProcessor): def pp_key(cls): return 'MoveFiles' + def expand_relative_paths(self, files_to_move, finaldir): + for filetype in self.FILETYPE_KEYS: + if filetype not in files_to_move: + continue + for file_attrs in files_to_move[filetype]: + if not os.path.isabs(file_attrs['final_filepath']): + file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) + if not os.path.isabs(file_attrs['current_filepath']): + file_attrs['current_filepath'] = os.path.abspath(file_attrs['current_filepath']) + + return files_to_move + + def write_filepath_into_info(self, info, filetype, file_attrs): + if filetype == 'media': + info['filepath'] = file_attrs['final_filepath'] + return + + elif filetype == 'thumbnails': + for filetype_dict in info[filetype]: + if filetype_dict['id'] == file_attrs['id']: + filetype_dict['filepath'] = file_attrs['final_filepath'] + + elif filetype == 'requested_subtitles': + lang = file_attrs['lang'] + if lang in info[filetype]: + info[filetype][lang]['filepath'] = file_attrs['final_filepath'] + def run(self, info): - dl_path, dl_name = os.path.split(encodeFilename(info['filepath'])) + dl_path, dl_name = os.path.split(info['filepath']) finaldir = info.get('__finaldir', dl_path) - finalpath = os.path.join(finaldir, dl_name) + info['__files_to_move']['media'] = [] + if self._downloaded: - info['__files_to_move'][info['filepath']] = decodeFilename(finalpath) + info['__files_to_move']['media'] = [{ 'current_filepath': info['filepath'], 'final_filepath': dl_name }] - make_newfilename = lambda old: decodeFilename(os.path.join(finaldir, os.path.basename(encodeFilename(old)))) - for oldfile, newfile in info['__files_to_move'].items(): - if not newfile: - newfile = make_newfilename(oldfile) - if os.path.abspath(encodeFilename(oldfile)) == os.path.abspath(encodeFilename(newfile)): - continue - if not os.path.exists(encodeFilename(oldfile)): - self.report_warning('File "%s" cannot be found' % oldfile) + files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) + + for filetype in self.FILETYPE_KEYS: + if filetype not in files_to_move: continue - if os.path.exists(encodeFilename(newfile)): - if self.get_param('overwrites', True): - self.report_warning('Replacing existing file "%s"' % newfile) - os.remove(encodeFilename(newfile)) - else: - self.report_warning( - 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' - % (oldfile, newfile)) + + for file_attrs in files_to_move[filetype]: + current_filepath = file_attrs['current_filepath'] + final_filepath = file_attrs['final_filepath'] + + if not current_filepath or not final_filepath: + continue + + if current_filepath == final_filepath: + # This ensures the infojson contains the full filepath even + # when --no-overwrites is used + self.write_filepath_into_info(info, filetype, file_attrs) continue - make_dir(newfile, PostProcessingError) - self.to_screen(f'Moving file "{oldfile}" to "{newfile}"') - shutil.move(oldfile, newfile) # os.rename cannot move between volumes - info['filepath'] = finalpath + if not os.path.exists(current_filepath): + self.report_warning('File "%s" cannot be found' % current_filepath) + continue + + if os.path.exists(final_filepath): + if self.get_param('overwrites', True): + self.report_warning('Replacing existing file "%s"' % final_filepath) + os.remove(final_filepath) + else: + self.report_warning( + 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' + % (current_filepath, final_filepath)) + continue + + make_dir(final_filepath, PostProcessingError) + self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') + shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes + self.write_filepath_into_info(info, filetype, file_attrs) + return [], info From c9d8184fe6567274de72c1a95ce9ec7da3d76f3d Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 23 Apr 2024 11:00:15 -0700 Subject: [PATCH 02/17] Ran flake8 --- yt_dlp/postprocessor/movefilesafterdownload.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index d990eedf6e..73d0d623c1 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -7,6 +7,7 @@ from ..utils import ( make_dir, ) + class MoveFilesAfterDownloadPP(PostProcessor): FILETYPE_KEYS = ['media', 'thumbnails', 'requested_subtitles'] @@ -51,7 +52,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): info['__files_to_move']['media'] = [] if self._downloaded: - info['__files_to_move']['media'] = [{ 'current_filepath': info['filepath'], 'final_filepath': dl_name }] + info['__files_to_move']['media'] = [{'current_filepath': info['filepath'], 'final_filepath': dl_name}] files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) From 5d51ddbbfc454d852eacd07444eb16aa02053c28 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 23 Apr 2024 11:04:46 -0700 Subject: [PATCH 03/17] Removed unneeded conditionals + return --- yt_dlp/postprocessor/movefilesafterdownload.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index 73d0d623c1..4e3344ebd5 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -21,8 +21,6 @@ class MoveFilesAfterDownloadPP(PostProcessor): def expand_relative_paths(self, files_to_move, finaldir): for filetype in self.FILETYPE_KEYS: - if filetype not in files_to_move: - continue for file_attrs in files_to_move[filetype]: if not os.path.isabs(file_attrs['final_filepath']): file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) @@ -34,7 +32,6 @@ class MoveFilesAfterDownloadPP(PostProcessor): def write_filepath_into_info(self, info, filetype, file_attrs): if filetype == 'media': info['filepath'] = file_attrs['final_filepath'] - return elif filetype == 'thumbnails': for filetype_dict in info[filetype]: From fe4a15ff75ca94dfdad3e83e1c7c0759d39efecf Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 23 Apr 2024 11:54:38 -0700 Subject: [PATCH 04/17] First pass at test feedback --- yt_dlp/postprocessor/movefilesafterdownload.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index 4e3344ebd5..cb4c1cd1c6 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -21,6 +21,9 @@ class MoveFilesAfterDownloadPP(PostProcessor): def expand_relative_paths(self, files_to_move, finaldir): for filetype in self.FILETYPE_KEYS: + if filetype not in files_to_move: + files_to_move[filetype] = [] + for file_attrs in files_to_move[filetype]: if not os.path.isabs(file_attrs['final_filepath']): file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) @@ -45,8 +48,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): def run(self, info): dl_path, dl_name = os.path.split(info['filepath']) - finaldir = info.get('__finaldir', dl_path) - info['__files_to_move']['media'] = [] + finaldir = info.get('__finaldir', os.path.abspath(dl_path)) if self._downloaded: info['__files_to_move']['media'] = [{'current_filepath': info['filepath'], 'final_filepath': dl_name}] @@ -54,9 +56,6 @@ class MoveFilesAfterDownloadPP(PostProcessor): files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) for filetype in self.FILETYPE_KEYS: - if filetype not in files_to_move: - continue - for file_attrs in files_to_move[filetype]: current_filepath = file_attrs['current_filepath'] final_filepath = file_attrs['final_filepath'] From 44bb6c205620d133a4772fb6de56786859aecfba Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Wed, 24 Apr 2024 09:47:58 -0700 Subject: [PATCH 05/17] [WIP] got refactor of file mover basically working --- yt_dlp/YoutubeDL.py | 28 +- .../postprocessor/movefilesafterdownload.py | 239 +++++++++++++----- yt_dlp/utils/_utils.py | 4 +- 3 files changed, 194 insertions(+), 77 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 5f652c6379..ea4e4fe084 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1982,8 +1982,9 @@ class YoutubeDL: 'playlist', ie_result, self.prepare_filename(ie_copy, 'pl_infojson')) if _infojson_written is None: return - if self._write_description('playlist', ie_result, - self.prepare_filename(ie_copy, 'pl_description')) is None: + + description_file = self._write_description('playlist', ie_result, self.prepare_filename(ie_copy, 'pl_description')) + if description_file is None: return # TODO: This should be passed to ThumbnailsConvertor if necessary self._write_thumbnails('playlist', ie_result, self.prepare_filename(ie_copy, 'pl_thumbnail')) @@ -3229,8 +3230,8 @@ class YoutubeDL: if not self._ensure_dir_exists(encodeFilename(temp_filename)): return - if self._write_description('video', info_dict, - self.prepare_filename(info_dict, 'description')) is None: + description_file = self._write_description('video', info_dict, self.prepare_filename(info_dict, 'description')) + if description_file is None: return sub_files = self._write_subtitles(info_dict, temp_filename) @@ -4245,27 +4246,28 @@ class YoutubeDL: self.report_error(f'Cannot write {label} metadata to JSON file {infofn}') return None - def _write_description(self, label, ie_result, descfn): + def _write_description(self, label, info_dict, filename): ''' Write description and returns True = written, False = skip, None = error ''' if not self.params.get('writedescription'): return False - elif not descfn: + elif not filename: self.write_debug(f'Skipping writing {label} description') return False - elif not self._ensure_dir_exists(descfn): + elif not self._ensure_dir_exists(filename): return None - elif not self.params.get('overwrites', True) and os.path.exists(descfn): + elif not self.params.get('overwrites', True) and os.path.exists(filename): self.to_screen(f'[info] {label.title()} description is already present') - elif ie_result.get('description') is None: + elif info_dict.get('description') is None: self.to_screen(f'[info] There\'s no {label} description to write') return False else: try: - self.to_screen(f'[info] Writing {label} description to: {descfn}') - with open(encodeFilename(descfn), 'w', encoding='utf-8') as descfile: - descfile.write(ie_result['description']) + self.to_screen(f'[info] Writing {label} description to: {filename}') + with open(filename, 'w', encoding='utf-8') as descfile: + descfile.write(info_dict['description']) + info_dict['description_filepath'] = filename except OSError: - self.report_error(f'Cannot write {label} description file {descfn}') + self.report_error(f'Cannot write {label} description file {filename}') return None return True diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index cb4c1cd1c6..b80ba68985 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -1,15 +1,23 @@ import os +from pathlib import Path from .common import PostProcessor from ..compat import shutil from ..utils import ( PostProcessingError, make_dir, + replace_extension ) - +import pdb class MoveFilesAfterDownloadPP(PostProcessor): - FILETYPE_KEYS = ['media', 'thumbnails', 'requested_subtitles'] + TOP_LEVEL_KEYS = ['filepath'] + # Map of the keys that contain moveable files and the 'type' of the file + # for generating the output filename + CHILD_KEYS = { + 'thumbnails': 'thumbnail', + 'requested_subtitles': 'subtitle' + } def __init__(self, downloader=None, downloaded=True): PostProcessor.__init__(self, downloader) @@ -18,74 +26,179 @@ class MoveFilesAfterDownloadPP(PostProcessor): @classmethod def pp_key(cls): return 'MoveFiles' - - def expand_relative_paths(self, files_to_move, finaldir): - for filetype in self.FILETYPE_KEYS: - if filetype not in files_to_move: - files_to_move[filetype] = [] - - for file_attrs in files_to_move[filetype]: - if not os.path.isabs(file_attrs['final_filepath']): - file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) - if not os.path.isabs(file_attrs['current_filepath']): - file_attrs['current_filepath'] = os.path.abspath(file_attrs['current_filepath']) - - return files_to_move - - def write_filepath_into_info(self, info, filetype, file_attrs): - if filetype == 'media': - info['filepath'] = file_attrs['final_filepath'] - - elif filetype == 'thumbnails': - for filetype_dict in info[filetype]: - if filetype_dict['id'] == file_attrs['id']: - filetype_dict['filepath'] = file_attrs['final_filepath'] - - elif filetype == 'requested_subtitles': - lang = file_attrs['lang'] - if lang in info[filetype]: - info[filetype][lang]['filepath'] = file_attrs['final_filepath'] + + def move_file_and_write_to_info(self, info_dict, relevant_dict, output_file_type): + if 'filepath' not in relevant_dict: + return + + output_file_type = output_file_type or '' + current_filepath = relevant_dict['filepath'] + # This approach is needed to preserved indexed thumbnail paths from `--write-all-thumbnails` + # and also to support user-defined extensions (eg: `%(title)s.temp.%(ext)s`) + extension = ''.join(Path(current_filepath).suffixes) + name_format = self._downloader.prepare_filename(info_dict, output_file_type) + final_filepath = replace_extension(name_format, extension) + move_result = self.move_file(info_dict, current_filepath, final_filepath) + + print('*******************') + print("output_file_type", output_file_type) + print("name_format", name_format) + print("current_filepath", current_filepath) + print("final_filepath", final_filepath) + print("move_result", move_result) + print('*******************') + + if move_result: + relevant_dict['filepath'] = move_result + else: + del relevant_dict['filepath'] + + def move_file(self, info_dict, current_filepath, final_filepath): + if not current_filepath or not final_filepath: + return + + dl_path, _dl_name = os.path.split(info_dict['filepath']) + finaldir = info_dict.get('__finaldir', os.path.abspath(dl_path)) + + if not os.path.isabs(current_filepath): + current_filepath = os.path.join(finaldir, current_filepath) + + if not os.path.isabs(final_filepath): + final_filepath = os.path.join(finaldir, final_filepath) + + if current_filepath == final_filepath: + return final_filepath + + if not os.path.exists(current_filepath): + self.report_warning('File "%s" cannot be found' % current_filepath) + return + + if os.path.exists(final_filepath): + if self.get_param('overwrites', True): + self.report_warning('Replacing existing file "%s"' % final_filepath) + os.remove(final_filepath) + else: + self.report_warning( + 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' + % (current_filepath, final_filepath)) + return + + make_dir(final_filepath, PostProcessingError) + self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') + shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes + + return final_filepath def run(self, info): dl_path, dl_name = os.path.split(info['filepath']) finaldir = info.get('__finaldir', os.path.abspath(dl_path)) + # TODO: add one single key to infodict with ALL downloaded files + # TODO: test with --path temp and stuff + # TODO: make the below work with not-currently-written filepaths like description, annotations, etc + # - Descriptions work, have to do all the other ones too + # - I lied, this should become another post-processor + # TODO: [DONE] probably something with relative paths into absolute again? + # TODO: remove all __files_to_move stuff when done + # TODO: add net-new filepaths to `sanitize_info` + # TODO: consider adding a `infojson_filepath` key in addition to the `infojson_filename` key where the former is the fullpath - if self._downloaded: - info['__files_to_move']['media'] = [{'current_filepath': info['filepath'], 'final_filepath': dl_name}] - - files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) - - for filetype in self.FILETYPE_KEYS: - for file_attrs in files_to_move[filetype]: - current_filepath = file_attrs['current_filepath'] - final_filepath = file_attrs['final_filepath'] + for filepath_key in self.TOP_LEVEL_KEYS: + self.move_file_and_write_to_info(info, info, None) - if not current_filepath or not final_filepath: - continue + for key, output_file_type in self.CHILD_KEYS.items(): + if key not in info: + continue - if current_filepath == final_filepath: - # This ensures the infojson contains the full filepath even - # when --no-overwrites is used - self.write_filepath_into_info(info, filetype, file_attrs) - continue + if isinstance(info[key], list) or isinstance(info[key], dict): + iterable = info[key].values() if isinstance(info[key], dict) else info[key] - if not os.path.exists(current_filepath): - self.report_warning('File "%s" cannot be found' % current_filepath) - continue - - if os.path.exists(final_filepath): - if self.get_param('overwrites', True): - self.report_warning('Replacing existing file "%s"' % final_filepath) - os.remove(final_filepath) - else: - self.report_warning( - 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' - % (current_filepath, final_filepath)) - continue - - make_dir(final_filepath, PostProcessingError) - self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') - shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes - self.write_filepath_into_info(info, filetype, file_attrs) + for file_dict in iterable: + self.move_file_and_write_to_info(info, file_dict, output_file_type) return [], info + +# class MoveFilesAfterDownloadPP(PostProcessor): +# FILETYPE_KEYS = ['media', 'thumbnails', 'requested_subtitles'] + +# def __init__(self, downloader=None, downloaded=True): +# PostProcessor.__init__(self, downloader) +# self._downloaded = downloaded + +# @classmethod +# def pp_key(cls): +# return 'MoveFiles' + +# def expand_relative_paths(self, files_to_move, finaldir): +# for filetype in self.FILETYPE_KEYS: +# if filetype not in files_to_move: +# files_to_move[filetype] = [] + +# for file_attrs in files_to_move[filetype]: +# if not os.path.isabs(file_attrs['final_filepath']): +# file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) +# if not os.path.isabs(file_attrs['current_filepath']): +# file_attrs['current_filepath'] = os.path.abspath(file_attrs['current_filepath']) + +# return files_to_move + +# def write_filepath_into_info(self, info, filetype, file_attrs): +# if filetype == 'media': +# info['filepath'] = file_attrs['final_filepath'] + +# elif filetype == 'thumbnails': +# for filetype_dict in info[filetype]: +# if filetype_dict['id'] == file_attrs['id']: +# filetype_dict['filepath'] = file_attrs['final_filepath'] + +# elif filetype == 'requested_subtitles': +# lang = file_attrs['lang'] +# if lang in info[filetype]: +# info[filetype][lang]['filepath'] = file_attrs['final_filepath'] + +# def run(self, info): +# dl_path, dl_name = os.path.split(info['filepath']) +# finaldir = info.get('__finaldir', os.path.abspath(dl_path)) + +# th = self._downloader.prepare_filename(info, 'thumbnail') +# pdb.set_trace() +# print("th", th) + +# if self._downloaded: +# info['__files_to_move']['media'] = [{'current_filepath': info['filepath'], 'final_filepath': dl_name}] + +# files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) + +# for filetype in self.FILETYPE_KEYS: +# for file_attrs in files_to_move[filetype]: +# current_filepath = file_attrs['current_filepath'] +# final_filepath = file_attrs['final_filepath'] + +# if not current_filepath or not final_filepath: +# continue + +# if current_filepath == final_filepath: +# # This ensures the infojson contains the full filepath even +# # when --no-overwrites is used +# self.write_filepath_into_info(info, filetype, file_attrs) +# continue + +# if not os.path.exists(current_filepath): +# self.report_warning('File "%s" cannot be found' % current_filepath) +# continue + +# if os.path.exists(final_filepath): +# if self.get_param('overwrites', True): +# self.report_warning('Replacing existing file "%s"' % final_filepath) +# os.remove(final_filepath) +# else: +# self.report_warning( +# 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' +# % (current_filepath, final_filepath)) +# continue + +# make_dir(final_filepath, PostProcessingError) +# self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') +# shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes +# self.write_filepath_into_info(info, filetype, file_attrs) + +# return [], info diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index e3e80f3d33..cb018dbfdd 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -2099,7 +2099,9 @@ def prepend_extension(filename, ext, expected_real_ext=None): def replace_extension(filename, ext, expected_real_ext=None): name, real_ext = os.path.splitext(filename) - return '{}.{}'.format( + ext = ext if ext.startswith('.') else '.' + ext + + return '{}{}'.format( name if not expected_real_ext or real_ext[1:] == expected_real_ext else filename, ext) From ea2a085397598e74934d231adcbb33438405ca1b Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Wed, 24 Apr 2024 10:57:39 -0700 Subject: [PATCH 06/17] Fixed up tests and linting --- test/test_YoutubeDL.py | 35 ++--- yt_dlp/YoutubeDL.py | 3 +- .../postprocessor/movefilesafterdownload.py | 125 ++---------------- 3 files changed, 29 insertions(+), 134 deletions(-) diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index 5242cf88f9..c873af4b42 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -874,32 +874,33 @@ class TestYoutubeDL(unittest.TestCase): }), r'^30fps$') def test_postprocessors(self): - filename = 'post-processor-testfile.mp4' - audiofile = filename + '.mp3' + filename = 'post-processor-testfile' + video_file = filename + '.mp4' + audio_file = filename + '.mp3' class SimplePP(PostProcessor): def run(self, info): - with open(audiofile, 'w') as f: + with open(audio_file, 'w') as f: f.write('EXAMPLE') return [info['filepath']], info def run_pp(params, PP): - with open(filename, 'w') as f: + with open(video_file, 'w') as f: f.write('EXAMPLE') ydl = YoutubeDL(params) ydl.add_post_processor(PP()) - ydl.post_process(filename, {'filepath': filename}) + ydl.post_process(video_file, {'filepath': video_file}) - run_pp({'keepvideo': True}, SimplePP) - self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename) - self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile) - os.unlink(filename) - os.unlink(audiofile) + run_pp({'keepvideo': True, 'outtmpl': filename}, SimplePP) + self.assertTrue(os.path.exists(video_file), '%s doesn\'t exist' % video_file) + self.assertTrue(os.path.exists(audio_file), '%s doesn\'t exist' % audio_file) + os.unlink(video_file) + os.unlink(audio_file) - run_pp({'keepvideo': False}, SimplePP) - self.assertFalse(os.path.exists(filename), '%s exists' % filename) - self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile) - os.unlink(audiofile) + run_pp({'keepvideo': False, 'outtmpl': filename}, SimplePP) + self.assertFalse(os.path.exists(video_file), '%s exists' % video_file) + self.assertTrue(os.path.exists(audio_file), '%s doesn\'t exist' % audio_file) + os.unlink(audio_file) class ModifierPP(PostProcessor): def run(self, info): @@ -907,9 +908,9 @@ class TestYoutubeDL(unittest.TestCase): f.write('MODIFIED') return [], info - run_pp({'keepvideo': False}, ModifierPP) - self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename) - os.unlink(filename) + run_pp({'keepvideo': False, 'outtmpl': filename}, ModifierPP) + self.assertTrue(os.path.exists(video_file), '%s doesn\'t exist' % video_file) + os.unlink(video_file) def test_match_filter(self): first = { diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index ea4e4fe084..f6921297d1 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1982,7 +1982,7 @@ class YoutubeDL: 'playlist', ie_result, self.prepare_filename(ie_copy, 'pl_infojson')) if _infojson_written is None: return - + description_file = self._write_description('playlist', ie_result, self.prepare_filename(ie_copy, 'pl_description')) if description_file is None: return @@ -4265,7 +4265,6 @@ class YoutubeDL: self.to_screen(f'[info] Writing {label} description to: {filename}') with open(filename, 'w', encoding='utf-8') as descfile: descfile.write(info_dict['description']) - info_dict['description_filepath'] = filename except OSError: self.report_error(f'Cannot write {label} description file {filename}') return None diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index b80ba68985..e56761bc06 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -8,7 +8,7 @@ from ..utils import ( make_dir, replace_extension ) -import pdb + class MoveFilesAfterDownloadPP(PostProcessor): TOP_LEVEL_KEYS = ['filepath'] @@ -26,8 +26,9 @@ class MoveFilesAfterDownloadPP(PostProcessor): @classmethod def pp_key(cls): return 'MoveFiles' - - def move_file_and_write_to_info(self, info_dict, relevant_dict, output_file_type): + + def move_file_and_write_to_info(self, info_dict, relevant_dict=None, output_file_type=None): + relevant_dict = relevant_dict or info_dict if 'filepath' not in relevant_dict: return @@ -39,14 +40,6 @@ class MoveFilesAfterDownloadPP(PostProcessor): name_format = self._downloader.prepare_filename(info_dict, output_file_type) final_filepath = replace_extension(name_format, extension) move_result = self.move_file(info_dict, current_filepath, final_filepath) - - print('*******************') - print("output_file_type", output_file_type) - print("name_format", name_format) - print("current_filepath", current_filepath) - print("final_filepath", final_filepath) - print("move_result", move_result) - print('*******************') if move_result: relevant_dict['filepath'] = move_result @@ -56,9 +49,9 @@ class MoveFilesAfterDownloadPP(PostProcessor): def move_file(self, info_dict, current_filepath, final_filepath): if not current_filepath or not final_filepath: return - - dl_path, _dl_name = os.path.split(info_dict['filepath']) - finaldir = info_dict.get('__finaldir', os.path.abspath(dl_path)) + + dl_parent_folder = os.path.split(info_dict['filepath'])[0] + finaldir = info_dict.get('__finaldir', os.path.abspath(dl_parent_folder)) if not os.path.isabs(current_filepath): current_filepath = os.path.join(finaldir, current_filepath) @@ -86,24 +79,12 @@ class MoveFilesAfterDownloadPP(PostProcessor): make_dir(final_filepath, PostProcessingError) self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes - + return final_filepath def run(self, info): - dl_path, dl_name = os.path.split(info['filepath']) - finaldir = info.get('__finaldir', os.path.abspath(dl_path)) - # TODO: add one single key to infodict with ALL downloaded files - # TODO: test with --path temp and stuff - # TODO: make the below work with not-currently-written filepaths like description, annotations, etc - # - Descriptions work, have to do all the other ones too - # - I lied, this should become another post-processor - # TODO: [DONE] probably something with relative paths into absolute again? - # TODO: remove all __files_to_move stuff when done - # TODO: add net-new filepaths to `sanitize_info` - # TODO: consider adding a `infojson_filepath` key in addition to the `infojson_filename` key where the former is the fullpath - - for filepath_key in self.TOP_LEVEL_KEYS: - self.move_file_and_write_to_info(info, info, None) + # This represents the main media file (using the 'filepath' key) + self.move_file_and_write_to_info(info) for key, output_file_type in self.CHILD_KEYS.items(): if key not in info: @@ -116,89 +97,3 @@ class MoveFilesAfterDownloadPP(PostProcessor): self.move_file_and_write_to_info(info, file_dict, output_file_type) return [], info - -# class MoveFilesAfterDownloadPP(PostProcessor): -# FILETYPE_KEYS = ['media', 'thumbnails', 'requested_subtitles'] - -# def __init__(self, downloader=None, downloaded=True): -# PostProcessor.__init__(self, downloader) -# self._downloaded = downloaded - -# @classmethod -# def pp_key(cls): -# return 'MoveFiles' - -# def expand_relative_paths(self, files_to_move, finaldir): -# for filetype in self.FILETYPE_KEYS: -# if filetype not in files_to_move: -# files_to_move[filetype] = [] - -# for file_attrs in files_to_move[filetype]: -# if not os.path.isabs(file_attrs['final_filepath']): -# file_attrs['final_filepath'] = os.path.join(finaldir, file_attrs['final_filepath']) -# if not os.path.isabs(file_attrs['current_filepath']): -# file_attrs['current_filepath'] = os.path.abspath(file_attrs['current_filepath']) - -# return files_to_move - -# def write_filepath_into_info(self, info, filetype, file_attrs): -# if filetype == 'media': -# info['filepath'] = file_attrs['final_filepath'] - -# elif filetype == 'thumbnails': -# for filetype_dict in info[filetype]: -# if filetype_dict['id'] == file_attrs['id']: -# filetype_dict['filepath'] = file_attrs['final_filepath'] - -# elif filetype == 'requested_subtitles': -# lang = file_attrs['lang'] -# if lang in info[filetype]: -# info[filetype][lang]['filepath'] = file_attrs['final_filepath'] - -# def run(self, info): -# dl_path, dl_name = os.path.split(info['filepath']) -# finaldir = info.get('__finaldir', os.path.abspath(dl_path)) - -# th = self._downloader.prepare_filename(info, 'thumbnail') -# pdb.set_trace() -# print("th", th) - -# if self._downloaded: -# info['__files_to_move']['media'] = [{'current_filepath': info['filepath'], 'final_filepath': dl_name}] - -# files_to_move = self.expand_relative_paths(info['__files_to_move'], finaldir) - -# for filetype in self.FILETYPE_KEYS: -# for file_attrs in files_to_move[filetype]: -# current_filepath = file_attrs['current_filepath'] -# final_filepath = file_attrs['final_filepath'] - -# if not current_filepath or not final_filepath: -# continue - -# if current_filepath == final_filepath: -# # This ensures the infojson contains the full filepath even -# # when --no-overwrites is used -# self.write_filepath_into_info(info, filetype, file_attrs) -# continue - -# if not os.path.exists(current_filepath): -# self.report_warning('File "%s" cannot be found' % current_filepath) -# continue - -# if os.path.exists(final_filepath): -# if self.get_param('overwrites', True): -# self.report_warning('Replacing existing file "%s"' % final_filepath) -# os.remove(final_filepath) -# else: -# self.report_warning( -# 'Cannot move file "%s" out of temporary directory since "%s" already exists. ' -# % (current_filepath, final_filepath)) -# continue - -# make_dir(final_filepath, PostProcessingError) -# self.to_screen(f'Moving file "{current_filepath}" to "{final_filepath}"') -# shutil.move(current_filepath, final_filepath) # os.rename cannot move between volumes -# self.write_filepath_into_info(info, filetype, file_attrs) - -# return [], info From 9c3b227db8f4889e496ff4ac65da426dcfc79e02 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Wed, 24 Apr 2024 11:02:26 -0700 Subject: [PATCH 07/17] Removed files_to_move logic --- yt_dlp/YoutubeDL.py | 33 ++++++++++----------------------- yt_dlp/postprocessor/ffmpeg.py | 15 --------------- 2 files changed, 10 insertions(+), 38 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index f6921297d1..06e9109e1a 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1808,7 +1808,7 @@ class YoutubeDL: info_copy['id'] = ie.get_temp_id(ie_result['url']) self.add_default_extra_info(info_copy, ie, ie_result['url']) self.add_extra_info(info_copy, extra_info) - info_copy, _ = self.pre_process(info_copy) + info_copy = self.pre_process(info_copy) self._fill_common_fields(info_copy, False) self.__forced_printings(info_copy) self._raise_pending_errors(info_copy) @@ -2885,13 +2885,13 @@ class YoutubeDL: # which can't be exported to json info_dict['formats'] = formats - info_dict, _ = self.pre_process(info_dict) + info_dict = self.pre_process(info_dict) if self._match_entry(info_dict, incomplete=self._format_fields) is not None: return info_dict self.post_extract(info_dict) - info_dict, _ = self.pre_process(info_dict, 'after_filter') + info_dict = self.pre_process(info_dict, 'after_filter') # The pre-processors may have modified the formats formats = self._get_formats(info_dict) @@ -3202,14 +3202,13 @@ class YoutubeDL: info_dict.clear() info_dict.update(new_info) - new_info, _ = self.pre_process(info_dict, 'video') + new_info = self.pre_process(info_dict, 'video') replace_info_dict(new_info) self._num_downloads += 1 # info_dict['_filename'] needs to be set for backward compatibility info_dict['_filename'] = full_filename = self.prepare_filename(info_dict, warn=True) temp_filename = self.prepare_filename(info_dict, 'temp') - files_to_move = {} # Forced printings self.__forced_printings(info_dict, full_filename, incomplete=('format' not in info_dict)) @@ -3238,15 +3237,11 @@ class YoutubeDL: if sub_files is None: return - files_to_move['requested_subtitles'] = sub_files - thumb_files = self._write_thumbnails( 'video', info_dict, temp_filename, self.prepare_filename(info_dict, 'thumbnail')) if thumb_files is None: return - files_to_move['thumbnails'] = thumb_files - infofn = self.prepare_filename(info_dict, 'infojson') _infojson_written = self._write_info_json('video', info_dict, infofn) if _infojson_written: @@ -3319,13 +3314,12 @@ class YoutubeDL: for link_type, should_write in write_links.items()): return - new_info, files_to_move = self.pre_process(info_dict, 'before_dl', files_to_move) + new_info = self.pre_process(info_dict, 'before_dl') replace_info_dict(new_info) if self.params.get('skip_download'): info_dict['filepath'] = temp_filename info_dict['__finaldir'] = os.path.dirname(os.path.abspath(encodeFilename(full_filename))) - info_dict['__files_to_move'] = files_to_move replace_info_dict(self.run_pp(MoveFilesAfterDownloadPP(self, False), info_dict)) info_dict['__write_download_archive'] = self.params.get('force_write_download_archive') else: @@ -3439,9 +3433,6 @@ class YoutubeDL: info_dict['__files_to_merge'] = downloaded # Even if there were no downloads, it is being merged only now info_dict['__real_download'] = True - else: - for file in downloaded: - files_to_move[file] = None else: # Just a single file dl_filename = existing_video_file(full_filename, temp_filename) @@ -3525,7 +3516,7 @@ class YoutubeDL: fixup() try: - replace_info_dict(self.post_process(dl_filename, info_dict, files_to_move)) + replace_info_dict(self.post_process(dl_filename, info_dict)) except PostProcessingError as err: self.report_error('Postprocessing: %s' % str(err)) return @@ -3662,8 +3653,7 @@ class YoutubeDL: def run_pp(self, pp, infodict): files_to_delete = [] - if '__files_to_move' not in infodict: - infodict['__files_to_move'] = {} + try: files_to_delete, infodict = pp.run(infodict) except PostProcessingError as e: @@ -3687,24 +3677,21 @@ class YoutubeDL: info = self.run_pp(pp, info) return info - def pre_process(self, ie_info, key='pre_process', files_to_move=None): + def pre_process(self, ie_info, key='pre_process'): info = dict(ie_info) - info['__files_to_move'] = files_to_move or {} try: info = self.run_all_pps(key, info) except PostProcessingError as err: msg = f'Preprocessing: {err}' info.setdefault('__pending_error', msg) self.report_error(msg, is_error=False) - return info, info.pop('__files_to_move', None) + return info - def post_process(self, filename, info, files_to_move=None): + def post_process(self, filename, info): """Run all the postprocessors on the given file.""" info['filepath'] = filename - info['__files_to_move'] = files_to_move or {} info = self.run_all_pps('post_process', info, additional_pps=info.get('__postprocessors')) info = self.run_pp(MoveFilesAfterDownloadPP(self), info) - del info['__files_to_move'] return self.run_all_pps('after_move', info) def _make_archive_id(self, info_dict): diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index e794c1358d..3c069c8c6a 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -1016,11 +1016,6 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor): 'filepath': new_file, } - for sub_info in info['__files_to_move']['requested_subtitles']: - if sub_info['lang'] == lang and sub_info['ext'] == sub['ext']: - sub_info['current_filepath'] = replace_extension(sub_info['current_filepath'], new_ext) - sub_info['final_filepath'] = replace_extension(sub_info['final_filepath'], new_ext) - return sub_filenames, info @@ -1095,11 +1090,6 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): os.replace(thumbnail_filename, webp_filename) thumbnail['filepath'] = webp_filename - for thumb_info in info['__files_to_move']['thumbnails']: - if thumb_info['id'] == thumbnail['id']: - thumb_info['current_filepath'] = replace_extension(thumbnail_filename, 'webp') - thumb_info['final_filepath'] = replace_extension(thumb_info['final_filepath'], 'webp') - @staticmethod def _options(target_ext): yield from ('-update', '1') @@ -1137,11 +1127,6 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): thumbnail_dict['filepath'] = self.convert_thumbnail(original_thumbnail, target_ext) files_to_delete.append(original_thumbnail) - for thumb_info in info['__files_to_move']['thumbnails']: - if thumb_info['id'] == thumbnail_dict['id']: - thumb_info['current_filepath'] = replace_extension(thumb_info['current_filepath'], target_ext) - thumb_info['final_filepath'] = replace_extension(thumb_info['final_filepath'], target_ext) - if not has_thumbnail: self.to_screen('There aren\'t any thumbnails to convert') return files_to_delete, info From 0a3c5aceb5451ba4acf85f8d5e9ebfc1f9b693f1 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Wed, 24 Apr 2024 11:08:21 -0700 Subject: [PATCH 08/17] Removed now-unneeded thumbnail/subtitle return values --- yt_dlp/YoutubeDL.py | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 06e9109e1a..5774bcb613 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -4282,12 +4282,6 @@ class YoutubeDL: if existing_sub: self.to_screen(f'[info] Video subtitle {sub_lang}.{sub_format} is already present') sub_info['filepath'] = existing_sub - ret.append({ - 'current_filepath': existing_sub, - 'final_filepath': sub_filename_final, - 'lang': sub_lang, - 'ext': sub_info['ext'] - }) continue @@ -4299,12 +4293,6 @@ class YoutubeDL: with open(sub_filename, 'w', encoding='utf-8', newline='') as subfile: subfile.write(sub_info['data']) sub_info['filepath'] = sub_filename - ret.append({ - 'current_filepath': sub_filename, - 'final_filepath': sub_filename_final, - 'lang': sub_lang, - 'ext': sub_info['ext'] - }) continue except OSError: @@ -4316,12 +4304,6 @@ class YoutubeDL: sub_copy.setdefault('http_headers', info_dict.get('http_headers')) self.dl(sub_filename, sub_copy, subtitle=True) sub_info['filepath'] = sub_filename - ret.append({ - 'current_filepath': sub_filename, - 'final_filepath': sub_filename_final, - 'lang': sub_lang, - 'ext': sub_info['ext'] - }) except (DownloadError, ExtractorError, IOError, OSError, ValueError) + network_exceptions as err: msg = f'Unable to download video subtitles for {sub_lang!r}: {err}' @@ -4363,11 +4345,6 @@ class YoutubeDL: self.to_screen('[info] %s is already present' % ( thumb_display_id if multiple else f'{label} thumbnail').capitalize()) t['filepath'] = existing_thumb - ret.append({ - 'current_filepath': existing_thumb, - 'final_filepath': thumb_filename_final, - 'id': t['id'] - }) else: self.to_screen(f'[info] Downloading {thumb_display_id} ...') @@ -4377,12 +4354,6 @@ class YoutubeDL: with open(encodeFilename(thumb_filename), 'wb') as thumbf: shutil.copyfileobj(uf, thumbf) - ret.append({ - 'current_filepath': thumb_filename, - 'final_filepath': thumb_filename_final, - 'id': t['id'] - }) - t['filepath'] = thumb_filename except network_exceptions as err: if isinstance(err, HTTPError) and err.status == 404: From a1ff1d427259df821ff87c9ce2b00b5077b64dea Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 13:55:07 -0700 Subject: [PATCH 09/17] Reverted unrelated changes --- yt_dlp/YoutubeDL.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 5774bcb613..07f6f05d93 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1982,9 +1982,8 @@ class YoutubeDL: 'playlist', ie_result, self.prepare_filename(ie_copy, 'pl_infojson')) if _infojson_written is None: return - - description_file = self._write_description('playlist', ie_result, self.prepare_filename(ie_copy, 'pl_description')) - if description_file is None: + if self._write_description('playlist', ie_result, + self.prepare_filename(ie_copy, 'pl_description')) is None: return # TODO: This should be passed to ThumbnailsConvertor if necessary self._write_thumbnails('playlist', ie_result, self.prepare_filename(ie_copy, 'pl_thumbnail')) @@ -3229,8 +3228,8 @@ class YoutubeDL: if not self._ensure_dir_exists(encodeFilename(temp_filename)): return - description_file = self._write_description('video', info_dict, self.prepare_filename(info_dict, 'description')) - if description_file is None: + if self._write_description('video', info_dict, + self.prepare_filename(info_dict, 'description')) is None: return sub_files = self._write_subtitles(info_dict, temp_filename) @@ -4233,27 +4232,27 @@ class YoutubeDL: self.report_error(f'Cannot write {label} metadata to JSON file {infofn}') return None - def _write_description(self, label, info_dict, filename): + def _write_description(self, label, ie_result, descfn): ''' Write description and returns True = written, False = skip, None = error ''' if not self.params.get('writedescription'): return False - elif not filename: + elif not descfn: self.write_debug(f'Skipping writing {label} description') return False - elif not self._ensure_dir_exists(filename): + elif not self._ensure_dir_exists(descfn): return None - elif not self.params.get('overwrites', True) and os.path.exists(filename): + elif not self.params.get('overwrites', True) and os.path.exists(descfn): self.to_screen(f'[info] {label.title()} description is already present') - elif info_dict.get('description') is None: + elif ie_result.get('description') is None: self.to_screen(f'[info] There\'s no {label} description to write') return False else: try: - self.to_screen(f'[info] Writing {label} description to: {filename}') - with open(filename, 'w', encoding='utf-8') as descfile: - descfile.write(info_dict['description']) + self.to_screen(f'[info] Writing {label} description to: {descfn}') + with open(encodeFilename(descfn), 'w', encoding='utf-8') as descfile: + descfile.write(ie_result['description']) except OSError: - self.report_error(f'Cannot write {label} description file {filename}') + self.report_error(f'Cannot write {label} description file {descfn}') return None return True From 28d505154644061451d3fcd1294d586352ddb79b Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 14:17:18 -0700 Subject: [PATCH 10/17] Reverted pre/post_process function signature --- yt_dlp/YoutubeDL.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 07f6f05d93..2ace14a3b2 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1808,7 +1808,7 @@ class YoutubeDL: info_copy['id'] = ie.get_temp_id(ie_result['url']) self.add_default_extra_info(info_copy, ie, ie_result['url']) self.add_extra_info(info_copy, extra_info) - info_copy = self.pre_process(info_copy) + info_copy, _ = self.pre_process(info_copy) self._fill_common_fields(info_copy, False) self.__forced_printings(info_copy) self._raise_pending_errors(info_copy) @@ -2884,13 +2884,13 @@ class YoutubeDL: # which can't be exported to json info_dict['formats'] = formats - info_dict = self.pre_process(info_dict) + info_dict, _ = self.pre_process(info_dict) if self._match_entry(info_dict, incomplete=self._format_fields) is not None: return info_dict self.post_extract(info_dict) - info_dict = self.pre_process(info_dict, 'after_filter') + info_dict, _ = self.pre_process(info_dict, 'after_filter') # The pre-processors may have modified the formats formats = self._get_formats(info_dict) @@ -3201,7 +3201,7 @@ class YoutubeDL: info_dict.clear() info_dict.update(new_info) - new_info = self.pre_process(info_dict, 'video') + new_info, _ = self.pre_process(info_dict, 'video') replace_info_dict(new_info) self._num_downloads += 1 @@ -3313,7 +3313,7 @@ class YoutubeDL: for link_type, should_write in write_links.items()): return - new_info = self.pre_process(info_dict, 'before_dl') + new_info, _ = self.pre_process(info_dict, 'before_dl') replace_info_dict(new_info) if self.params.get('skip_download'): @@ -3676,7 +3676,10 @@ class YoutubeDL: info = self.run_pp(pp, info) return info - def pre_process(self, ie_info, key='pre_process'): + def pre_process(self, ie_info, key='pre_process', files_to_move=None): + if files_to_move is not None: + self.report_warning('[pre_process] "files_to_move" is deprecated and may be removed in a future version') + info = dict(ie_info) try: info = self.run_all_pps(key, info) @@ -3684,10 +3687,13 @@ class YoutubeDL: msg = f'Preprocessing: {err}' info.setdefault('__pending_error', msg) self.report_error(msg, is_error=False) - return info + return info, files_to_move - def post_process(self, filename, info): + def post_process(self, filename, info, files_to_move=None): """Run all the postprocessors on the given file.""" + if files_to_move is not None: + self.report_warning('[post_process] "files_to_move" is deprecated and may be removed in a future version') + info['filepath'] = filename info = self.run_all_pps('post_process', info, additional_pps=info.get('__postprocessors')) info = self.run_pp(MoveFilesAfterDownloadPP(self), info) @@ -4281,7 +4287,7 @@ class YoutubeDL: if existing_sub: self.to_screen(f'[info] Video subtitle {sub_lang}.{sub_format} is already present') sub_info['filepath'] = existing_sub - + ret.append((existing_sub, sub_filename_final)) continue self.to_screen(f'[info] Writing video subtitles to: {sub_filename}') @@ -4292,7 +4298,7 @@ class YoutubeDL: with open(sub_filename, 'w', encoding='utf-8', newline='') as subfile: subfile.write(sub_info['data']) sub_info['filepath'] = sub_filename - + ret.append((sub_filename, sub_filename_final)) continue except OSError: self.report_error(f'Cannot write video subtitles file {sub_filename}') @@ -4303,7 +4309,7 @@ class YoutubeDL: sub_copy.setdefault('http_headers', info_dict.get('http_headers')) self.dl(sub_filename, sub_copy, subtitle=True) sub_info['filepath'] = sub_filename - + ret.append((sub_filename, sub_filename_final)) except (DownloadError, ExtractorError, IOError, OSError, ValueError) + network_exceptions as err: msg = f'Unable to download video subtitles for {sub_lang!r}: {err}' if self.params.get('ignoreerrors') is not True: # False or 'only_download' @@ -4344,7 +4350,7 @@ class YoutubeDL: self.to_screen('[info] %s is already present' % ( thumb_display_id if multiple else f'{label} thumbnail').capitalize()) t['filepath'] = existing_thumb - + ret.append((existing_thumb, thumb_filename_final)) else: self.to_screen(f'[info] Downloading {thumb_display_id} ...') try: @@ -4352,7 +4358,7 @@ class YoutubeDL: self.to_screen(f'[info] Writing {thumb_display_id} to: {thumb_filename}') with open(encodeFilename(thumb_filename), 'wb') as thumbf: shutil.copyfileobj(uf, thumbf) - + ret.append((thumb_filename, thumb_filename_final)) t['filepath'] = thumb_filename except network_exceptions as err: if isinstance(err, HTTPError) and err.status == 404: From c3fccc58cfce89cd8758c357d8265775e7f36c87 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 15:26:26 -0700 Subject: [PATCH 11/17] Updated logic for determining file extensions --- yt_dlp/YoutubeDL.py | 12 ++++---- .../postprocessor/movefilesafterdownload.py | 29 ++++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 2ace14a3b2..dca355b022 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -3697,6 +3697,7 @@ class YoutubeDL: info['filepath'] = filename info = self.run_all_pps('post_process', info, additional_pps=info.get('__postprocessors')) info = self.run_pp(MoveFilesAfterDownloadPP(self), info) + del info['__multiple_thumbnails'] return self.run_all_pps('after_move', info) def _make_archive_id(self, info_dict): @@ -4287,7 +4288,7 @@ class YoutubeDL: if existing_sub: self.to_screen(f'[info] Video subtitle {sub_lang}.{sub_format} is already present') sub_info['filepath'] = existing_sub - ret.append((existing_sub, sub_filename_final)) + ret.append(existing_sub) continue self.to_screen(f'[info] Writing video subtitles to: {sub_filename}') @@ -4298,7 +4299,7 @@ class YoutubeDL: with open(sub_filename, 'w', encoding='utf-8', newline='') as subfile: subfile.write(sub_info['data']) sub_info['filepath'] = sub_filename - ret.append((sub_filename, sub_filename_final)) + ret.append(sub_filename) continue except OSError: self.report_error(f'Cannot write video subtitles file {sub_filename}') @@ -4309,7 +4310,7 @@ class YoutubeDL: sub_copy.setdefault('http_headers', info_dict.get('http_headers')) self.dl(sub_filename, sub_copy, subtitle=True) sub_info['filepath'] = sub_filename - ret.append((sub_filename, sub_filename_final)) + ret.append(sub_filename) except (DownloadError, ExtractorError, IOError, OSError, ValueError) + network_exceptions as err: msg = f'Unable to download video subtitles for {sub_lang!r}: {err}' if self.params.get('ignoreerrors') is not True: # False or 'only_download' @@ -4329,6 +4330,7 @@ class YoutubeDL: self.to_screen(f'[info] There are no {label} thumbnails to download') return ret multiple = write_all and len(thumbnails) > 1 + info_dict['__multiple_thumbnails'] = multiple if thumb_filename_base is None: thumb_filename_base = filename @@ -4350,7 +4352,7 @@ class YoutubeDL: self.to_screen('[info] %s is already present' % ( thumb_display_id if multiple else f'{label} thumbnail').capitalize()) t['filepath'] = existing_thumb - ret.append((existing_thumb, thumb_filename_final)) + ret.append(existing_thumb) else: self.to_screen(f'[info] Downloading {thumb_display_id} ...') try: @@ -4358,7 +4360,7 @@ class YoutubeDL: self.to_screen(f'[info] Writing {thumb_display_id} to: {thumb_filename}') with open(encodeFilename(thumb_filename), 'wb') as thumbf: shutil.copyfileobj(uf, thumbf) - ret.append((thumb_filename, thumb_filename_final)) + ret.append(thumb_filename) t['filepath'] = thumb_filename except network_exceptions as err: if isinstance(err, HTTPError) and err.status == 404: diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index e56761bc06..e8ba86d78d 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -8,10 +8,10 @@ from ..utils import ( make_dir, replace_extension ) +import pdb class MoveFilesAfterDownloadPP(PostProcessor): - TOP_LEVEL_KEYS = ['filepath'] # Map of the keys that contain moveable files and the 'type' of the file # for generating the output filename CHILD_KEYS = { @@ -33,12 +33,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): return output_file_type = output_file_type or '' - current_filepath = relevant_dict['filepath'] - # This approach is needed to preserved indexed thumbnail paths from `--write-all-thumbnails` - # and also to support user-defined extensions (eg: `%(title)s.temp.%(ext)s`) - extension = ''.join(Path(current_filepath).suffixes) - name_format = self._downloader.prepare_filename(info_dict, output_file_type) - final_filepath = replace_extension(name_format, extension) + current_filepath, final_filepath = self.determine_filepath(info_dict, relevant_dict, output_file_type) move_result = self.move_file(info_dict, current_filepath, final_filepath) if move_result: @@ -46,6 +41,17 @@ class MoveFilesAfterDownloadPP(PostProcessor): else: del relevant_dict['filepath'] + def determine_filepath(self, info_dict, relevant_dict, output_file_type): + current_filepath = relevant_dict['filepath'] + prepared_filepath = self._downloader.prepare_filename(info_dict, output_file_type) + + if (output_file_type == 'thumbnail' and info_dict['__multiple_thumbnails']) or output_file_type == 'subtitle': + desired_extension = ''.join(Path(current_filepath).suffixes[-2:]) + else: + desired_extension = Path(current_filepath).suffix + + return current_filepath, replace_extension(prepared_filepath, desired_extension) + def move_file(self, info_dict, current_filepath, final_filepath): if not current_filepath or not final_filepath: return @@ -83,10 +89,17 @@ class MoveFilesAfterDownloadPP(PostProcessor): return final_filepath def run(self, info): + # Map of the keys that contain moveable files and the 'type' of the file + # for generating the output filename + child_keys = { + 'thumbnails': 'thumbnail', + 'requested_subtitles': 'subtitle' + } + # This represents the main media file (using the 'filepath' key) self.move_file_and_write_to_info(info) - for key, output_file_type in self.CHILD_KEYS.items(): + for key, output_file_type in child_keys.items(): if key not in info: continue From dd986a414983cf4e64be777e17f517c5915b88e3 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 15:31:22 -0700 Subject: [PATCH 12/17] Linter --- yt_dlp/postprocessor/movefilesafterdownload.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index e8ba86d78d..b0a17c5f07 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -8,7 +8,6 @@ from ..utils import ( make_dir, replace_extension ) -import pdb class MoveFilesAfterDownloadPP(PostProcessor): @@ -89,17 +88,10 @@ class MoveFilesAfterDownloadPP(PostProcessor): return final_filepath def run(self, info): - # Map of the keys that contain moveable files and the 'type' of the file - # for generating the output filename - child_keys = { - 'thumbnails': 'thumbnail', - 'requested_subtitles': 'subtitle' - } - # This represents the main media file (using the 'filepath' key) self.move_file_and_write_to_info(info) - for key, output_file_type in child_keys.items(): + for key, output_file_type in self.CHILD_KEYS.items(): if key not in info: continue From 3046c17822cef47353b9e45b8d05368c4094b23a Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 15:51:37 -0700 Subject: [PATCH 13/17] Fixed filepath bug when embedding thumbnails --- yt_dlp/postprocessor/embedthumbnail.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/yt_dlp/postprocessor/embedthumbnail.py b/yt_dlp/postprocessor/embedthumbnail.py index 9c5372956c..559fbfd449 100644 --- a/yt_dlp/postprocessor/embedthumbnail.py +++ b/yt_dlp/postprocessor/embedthumbnail.py @@ -224,4 +224,8 @@ class EmbedThumbnailPP(FFmpegPostProcessor): thumbnail_filename if converted or not self._already_have_thumbnail else None, original_thumbnail if converted and not self._already_have_thumbnail else None, info=info) + + if not self._already_have_thumbnail: + del info['thumbnails'][idx]['filepath'] + return [], info From 6c8ede8188eaf0bdea6e2cf48d3d460dce2ccf9d Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 26 Apr 2024 16:16:56 -0700 Subject: [PATCH 14/17] Fixed embedding filepath issue for subs and infojson --- yt_dlp/YoutubeDL.py | 2 +- yt_dlp/postprocessor/embedthumbnail.py | 2 +- yt_dlp/postprocessor/ffmpeg.py | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index dca355b022..d65d771fc0 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -3697,7 +3697,7 @@ class YoutubeDL: info['filepath'] = filename info = self.run_all_pps('post_process', info, additional_pps=info.get('__postprocessors')) info = self.run_pp(MoveFilesAfterDownloadPP(self), info) - del info['__multiple_thumbnails'] + info.pop('__multiple_thumbnails', None) return self.run_all_pps('after_move', info) def _make_archive_id(self, info_dict): diff --git a/yt_dlp/postprocessor/embedthumbnail.py b/yt_dlp/postprocessor/embedthumbnail.py index 559fbfd449..cc148ab202 100644 --- a/yt_dlp/postprocessor/embedthumbnail.py +++ b/yt_dlp/postprocessor/embedthumbnail.py @@ -226,6 +226,6 @@ class EmbedThumbnailPP(FFmpegPostProcessor): info=info) if not self._already_have_thumbnail: - del info['thumbnails'][idx]['filepath'] + info['thumbnails'][idx].pop('filepath', None) return [], info diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 3c069c8c6a..6492ebe1f9 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -662,6 +662,10 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor): self.run_ffmpeg_multiple_files(input_files, temp_filename, opts) os.replace(temp_filename, filename) + if not self._already_have_subtitle: + for _, subtitle in subtitles.items(): + subtitle.pop('filepath', None) + files_to_delete = [] if self._already_have_subtitle else sub_filenames return files_to_delete, info @@ -698,6 +702,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor): infojson_filename = info.get('infojson_filename') options.extend(self._get_infojson_opts(info, infojson_filename)) if not infojson_filename: + info.pop('infojson_filename', None) files_to_delete.append(info.get('infojson_filename')) elif self._add_infojson is True: self.to_screen('The info-json can only be attached to mkv/mka files') From 15c7bef8d06ee3214be583e70cfb31b50827d9c2 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 14 Jun 2024 12:47:59 -0700 Subject: [PATCH 15/17] Linting --- yt_dlp/postprocessor/movefilesafterdownload.py | 6 +++--- yt_dlp/utils/_utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index 590b3e3149..ed544dc13a 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -6,7 +6,7 @@ from ..compat import shutil from ..utils import ( PostProcessingError, make_dir, - replace_extension + replace_extension, ) @@ -15,7 +15,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): # for generating the output filename CHILD_KEYS = { 'thumbnails': 'thumbnail', - 'requested_subtitles': 'subtitle' + 'requested_subtitles': 'subtitle', } def __init__(self, downloader=None, downloaded=True): @@ -93,7 +93,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): if key not in info: continue - if isinstance(info[key], list) or isinstance(info[key], dict): + if isinstance(info[key], (dict, list)): iterable = info[key].values() if isinstance(info[key], dict) else info[key] for file_dict in iterable: diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index f1c2553e3f..c3b741c0f1 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -2106,7 +2106,7 @@ def check_executable(exe, args=[]): try: Popen.run([exe, *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: - return False + return False return exe From 7316fc57032e17b7624ea30cb2acb5965adb6e8f Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Fri, 14 Jun 2024 12:50:24 -0700 Subject: [PATCH 16/17] Missed one linting item --- test/test_YoutubeDL.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index 71e51b23c3..6579a9c46a 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -883,11 +883,11 @@ class TestYoutubeDL(unittest.TestCase): f.write('EXAMPLE') return [info['filepath']], info - def run_pp(params, PP): + def run_pp(params, pp): with open(video_file, 'w') as f: f.write('EXAMPLE') ydl = YoutubeDL(params) - ydl.add_post_processor(PP()) + ydl.add_post_processor(pp()) ydl.post_process(video_file, {'filepath': video_file}) run_pp({'keepvideo': True, 'outtmpl': filename}, SimplePP) From b3f1ef087afbf8ab666795dd9a01a9abfdd7a731 Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Mon, 8 Jul 2024 05:11:49 +0000 Subject: [PATCH 17/17] (merge conflict resolution) don't pass the dot to `replace_extension` --- yt_dlp/postprocessor/movefilesafterdownload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/postprocessor/movefilesafterdownload.py b/yt_dlp/postprocessor/movefilesafterdownload.py index ed544dc13a..149d684479 100644 --- a/yt_dlp/postprocessor/movefilesafterdownload.py +++ b/yt_dlp/postprocessor/movefilesafterdownload.py @@ -49,7 +49,7 @@ class MoveFilesAfterDownloadPP(PostProcessor): else: desired_extension = Path(current_filepath).suffix - return current_filepath, replace_extension(prepared_filepath, desired_extension) + return current_filepath, replace_extension(prepared_filepath, desired_extension[1:]) def move_file(self, info_dict, current_filepath, final_filepath): if not current_filepath or not final_filepath: