Postprocessors: use a list for the files that can be deleted
We could only know if we had to delete the original file, but this system allows to specify us more files (like subtitles).
This commit is contained in:
parent
53faa3ca5f
commit
592e97e855
8 changed files with 48 additions and 38 deletions
|
@ -443,27 +443,36 @@ class TestYoutubeDL(unittest.TestCase):
|
||||||
def run(self, info):
|
def run(self, info):
|
||||||
with open(audiofile, 'wt') as f:
|
with open(audiofile, 'wt') as f:
|
||||||
f.write('EXAMPLE')
|
f.write('EXAMPLE')
|
||||||
info['filepath']
|
return [info['filepath']], info
|
||||||
return False, info
|
|
||||||
|
|
||||||
def run_pp(params):
|
def run_pp(params, PP):
|
||||||
with open(filename, 'wt') as f:
|
with open(filename, 'wt') as f:
|
||||||
f.write('EXAMPLE')
|
f.write('EXAMPLE')
|
||||||
ydl = YoutubeDL(params)
|
ydl = YoutubeDL(params)
|
||||||
ydl.add_post_processor(SimplePP())
|
ydl.add_post_processor(PP())
|
||||||
ydl.post_process(filename, {'filepath': filename})
|
ydl.post_process(filename, {'filepath': filename})
|
||||||
|
|
||||||
run_pp({'keepvideo': True})
|
run_pp({'keepvideo': True}, SimplePP)
|
||||||
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
|
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
|
||||||
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
os.unlink(audiofile)
|
os.unlink(audiofile)
|
||||||
|
|
||||||
run_pp({'keepvideo': False})
|
run_pp({'keepvideo': False}, SimplePP)
|
||||||
self.assertFalse(os.path.exists(filename), '%s exists' % filename)
|
self.assertFalse(os.path.exists(filename), '%s exists' % filename)
|
||||||
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
||||||
os.unlink(audiofile)
|
os.unlink(audiofile)
|
||||||
|
|
||||||
|
class ModifierPP(PostProcessor):
|
||||||
|
def run(self, info):
|
||||||
|
with open(info['filepath'], 'wt') as f:
|
||||||
|
f.write('MODIFIED')
|
||||||
|
return [], info
|
||||||
|
|
||||||
|
run_pp({'keepvideo': False}, ModifierPP)
|
||||||
|
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
|
||||||
|
os.unlink(filename)
|
||||||
|
|
||||||
def test_match_filter(self):
|
def test_match_filter(self):
|
||||||
class FilterYDL(YDL):
|
class FilterYDL(YDL):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -1488,15 +1488,16 @@ class YoutubeDL(object):
|
||||||
for pp in pps_chain:
|
for pp in pps_chain:
|
||||||
old_filename = info['filepath']
|
old_filename = info['filepath']
|
||||||
try:
|
try:
|
||||||
keep_video, info = pp.run(info)
|
files_to_delete, info = pp.run(info)
|
||||||
except PostProcessingError as e:
|
except PostProcessingError as e:
|
||||||
self.report_error(e.msg)
|
self.report_error(e.msg)
|
||||||
if keep_video is False and not self.params.get('keepvideo', False):
|
if files_to_delete and not self.params.get('keepvideo', False):
|
||||||
try:
|
for old_filename in files_to_delete:
|
||||||
self.to_screen('Deleting original file %s (pass -k to keep)' % old_filename)
|
self.to_screen('Deleting original file %s (pass -k to keep)' % old_filename)
|
||||||
|
try:
|
||||||
os.remove(encodeFilename(old_filename))
|
os.remove(encodeFilename(old_filename))
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
self.report_warning('Unable to remove downloaded video file')
|
self.report_warning('Unable to remove downloaded original file')
|
||||||
|
|
||||||
def _make_archive_id(self, info_dict):
|
def _make_archive_id(self, info_dict):
|
||||||
# Future-proof against any change in case
|
# Future-proof against any change in case
|
||||||
|
|
|
@ -59,4 +59,4 @@ class AtomicParsleyPP(PostProcessor):
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
|
@ -42,14 +42,14 @@ class PostProcessor(object):
|
||||||
one has an extra field called "filepath" that points to the
|
one has an extra field called "filepath" that points to the
|
||||||
downloaded file.
|
downloaded file.
|
||||||
|
|
||||||
This method returns a tuple, the first element of which describes
|
This method returns a tuple, the first element is a list of the files
|
||||||
whether the original file should be kept (i.e. not deleted - None for
|
that can be deleted, and the second of which is the updated
|
||||||
no preference), and the second of which is the updated information.
|
information.
|
||||||
|
|
||||||
In addition, this method may raise a PostProcessingError
|
In addition, this method may raise a PostProcessingError
|
||||||
exception if post processing fails.
|
exception if post processing fails.
|
||||||
"""
|
"""
|
||||||
return None, information # by default, keep file and do nothing
|
return [], information # by default, keep file and do nothing
|
||||||
|
|
||||||
def try_utime(self, path, atime, mtime, errnote='Cannot update utime of file'):
|
def try_utime(self, path, atime, mtime, errnote='Cannot update utime of file'):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -25,4 +25,4 @@ class ExecAfterDownloadPP(PostProcessor):
|
||||||
raise PostProcessingError(
|
raise PostProcessingError(
|
||||||
'Command returned error code %d' % retCode)
|
'Command returned error code %d' % retCode)
|
||||||
|
|
||||||
return None, information # by default, keep file and do nothing
|
return [], information
|
||||||
|
|
|
@ -267,7 +267,7 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor):
|
||||||
if (new_path == path or
|
if (new_path == path or
|
||||||
(self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))):
|
(self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))):
|
||||||
self._downloader.to_screen('[youtube] Post-process file %s exists, skipping' % new_path)
|
self._downloader.to_screen('[youtube] Post-process file %s exists, skipping' % new_path)
|
||||||
return True, information
|
return [], information
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._downloader.to_screen('[' + self.basename + '] Destination: ' + new_path)
|
self._downloader.to_screen('[' + self.basename + '] Destination: ' + new_path)
|
||||||
|
@ -285,7 +285,7 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor):
|
||||||
errnote='Cannot update utime of audio file')
|
errnote='Cannot update utime of audio file')
|
||||||
|
|
||||||
information['filepath'] = new_path
|
information['filepath'] = new_path
|
||||||
return False, information
|
return [path], information
|
||||||
|
|
||||||
|
|
||||||
class FFmpegVideoConvertorPP(FFmpegPostProcessor):
|
class FFmpegVideoConvertorPP(FFmpegPostProcessor):
|
||||||
|
@ -299,13 +299,13 @@ class FFmpegVideoConvertorPP(FFmpegPostProcessor):
|
||||||
outpath = prefix + sep + self._preferedformat
|
outpath = prefix + sep + self._preferedformat
|
||||||
if information['ext'] == self._preferedformat:
|
if information['ext'] == self._preferedformat:
|
||||||
self._downloader.to_screen('[ffmpeg] Not converting video file %s - already is in target format %s' % (path, self._preferedformat))
|
self._downloader.to_screen('[ffmpeg] Not converting video file %s - already is in target format %s' % (path, self._preferedformat))
|
||||||
return True, information
|
return [], information
|
||||||
self._downloader.to_screen('[' + 'ffmpeg' + '] Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
|
self._downloader.to_screen('[' + 'ffmpeg' + '] Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
|
||||||
self.run_ffmpeg(path, outpath, [])
|
self.run_ffmpeg(path, outpath, [])
|
||||||
information['filepath'] = outpath
|
information['filepath'] = outpath
|
||||||
information['format'] = self._preferedformat
|
information['format'] = self._preferedformat
|
||||||
information['ext'] = self._preferedformat
|
information['ext'] = self._preferedformat
|
||||||
return False, information
|
return [path], information
|
||||||
|
|
||||||
|
|
||||||
class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
|
class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
|
||||||
|
@ -505,11 +505,11 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
|
||||||
def run(self, information):
|
def run(self, information):
|
||||||
if information['ext'] != 'mp4':
|
if information['ext'] != 'mp4':
|
||||||
self._downloader.to_screen('[ffmpeg] Subtitles can only be embedded in mp4 files')
|
self._downloader.to_screen('[ffmpeg] Subtitles can only be embedded in mp4 files')
|
||||||
return True, information
|
return [], information
|
||||||
subtitles = information.get('requested_subtitles')
|
subtitles = information.get('requested_subtitles')
|
||||||
if not subtitles:
|
if not subtitles:
|
||||||
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to embed')
|
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to embed')
|
||||||
return True, information
|
return [], information
|
||||||
|
|
||||||
sub_langs = list(subtitles.keys())
|
sub_langs = list(subtitles.keys())
|
||||||
filename = information['filepath']
|
filename = information['filepath']
|
||||||
|
@ -535,7 +535,7 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
|
|
||||||
return True, information
|
return [], information
|
||||||
|
|
||||||
|
|
||||||
class FFmpegMetadataPP(FFmpegPostProcessor):
|
class FFmpegMetadataPP(FFmpegPostProcessor):
|
||||||
|
@ -561,7 +561,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
|
||||||
|
|
||||||
if not metadata:
|
if not metadata:
|
||||||
self._downloader.to_screen('[ffmpeg] There isn\'t any metadata to add')
|
self._downloader.to_screen('[ffmpeg] There isn\'t any metadata to add')
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
filename = info['filepath']
|
filename = info['filepath']
|
||||||
temp_filename = prepend_extension(filename, 'temp')
|
temp_filename = prepend_extension(filename, 'temp')
|
||||||
|
@ -578,7 +578,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
|
||||||
self.run_ffmpeg(filename, temp_filename, options)
|
self.run_ffmpeg(filename, temp_filename, options)
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
|
|
||||||
class FFmpegMergerPP(FFmpegPostProcessor):
|
class FFmpegMergerPP(FFmpegPostProcessor):
|
||||||
|
@ -587,7 +587,7 @@ class FFmpegMergerPP(FFmpegPostProcessor):
|
||||||
args = ['-c', 'copy', '-map', '0:v:0', '-map', '1:a:0']
|
args = ['-c', 'copy', '-map', '0:v:0', '-map', '1:a:0']
|
||||||
self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename)
|
self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename)
|
||||||
self.run_ffmpeg_multiple_files(info['__files_to_merge'], filename, args)
|
self.run_ffmpeg_multiple_files(info['__files_to_merge'], filename, args)
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
|
|
||||||
class FFmpegAudioFixPP(FFmpegPostProcessor):
|
class FFmpegAudioFixPP(FFmpegPostProcessor):
|
||||||
|
@ -602,14 +602,14 @@ class FFmpegAudioFixPP(FFmpegPostProcessor):
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
|
|
||||||
class FFmpegFixupStretchedPP(FFmpegPostProcessor):
|
class FFmpegFixupStretchedPP(FFmpegPostProcessor):
|
||||||
def run(self, info):
|
def run(self, info):
|
||||||
stretched_ratio = info.get('stretched_ratio')
|
stretched_ratio = info.get('stretched_ratio')
|
||||||
if stretched_ratio is None or stretched_ratio == 1:
|
if stretched_ratio is None or stretched_ratio == 1:
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
filename = info['filepath']
|
filename = info['filepath']
|
||||||
temp_filename = prepend_extension(filename, 'temp')
|
temp_filename = prepend_extension(filename, 'temp')
|
||||||
|
@ -621,13 +621,13 @@ class FFmpegFixupStretchedPP(FFmpegPostProcessor):
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
|
|
||||||
class FFmpegFixupM4aPP(FFmpegPostProcessor):
|
class FFmpegFixupM4aPP(FFmpegPostProcessor):
|
||||||
def run(self, info):
|
def run(self, info):
|
||||||
if info.get('container') != 'm4a_dash':
|
if info.get('container') != 'm4a_dash':
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
filename = info['filepath']
|
filename = info['filepath']
|
||||||
temp_filename = prepend_extension(filename, 'temp')
|
temp_filename = prepend_extension(filename, 'temp')
|
||||||
|
@ -639,7 +639,7 @@ class FFmpegFixupM4aPP(FFmpegPostProcessor):
|
||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
|
|
||||||
class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
|
class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
|
||||||
|
@ -656,7 +656,7 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
|
||||||
new_format = 'webvtt'
|
new_format = 'webvtt'
|
||||||
if subs is None:
|
if subs is None:
|
||||||
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to convert')
|
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to convert')
|
||||||
return True, info
|
return [], info
|
||||||
self._downloader.to_screen('[ffmpeg] Converting subtitles')
|
self._downloader.to_screen('[ffmpeg] Converting subtitles')
|
||||||
for lang, sub in subs.items():
|
for lang, sub in subs.items():
|
||||||
ext = sub['ext']
|
ext = sub['ext']
|
||||||
|
@ -676,4 +676,4 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
|
||||||
'data': f.read(),
|
'data': f.read(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
|
@ -44,4 +44,4 @@ class MetadataFromTitlePP(PostProcessor):
|
||||||
info[attribute] = value
|
info[attribute] = value
|
||||||
self._downloader.to_screen('[fromtitle] parsed ' + attribute + ': ' + value)
|
self._downloader.to_screen('[fromtitle] parsed ' + attribute + ': ' + value)
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
|
@ -105,8 +105,8 @@ class XAttrMetadataPP(PostProcessor):
|
||||||
byte_value = value.encode('utf-8')
|
byte_value = value.encode('utf-8')
|
||||||
write_xattr(filename, xattrname, byte_value)
|
write_xattr(filename, xattrname, byte_value)
|
||||||
|
|
||||||
return True, info
|
return [], info
|
||||||
|
|
||||||
except (subprocess.CalledProcessError, OSError):
|
except (subprocess.CalledProcessError, OSError):
|
||||||
self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)")
|
self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)")
|
||||||
return False, info
|
return [], info
|
||||||
|
|
Loading…
Reference in a new issue