mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-03-09 12:50:23 -05:00
Rewrite
This commit is contained in:
parent
54792c9da8
commit
b18cc9c633
5 changed files with 70 additions and 62 deletions
|
@ -1002,9 +1002,7 @@ ## Post-Processing Options:
|
|||
--no-post-overwrites Do not overwrite post-processed files
|
||||
--embed-subs Embed subtitles in downloaded media.
|
||||
Available for video (mp4, webm, mkv) and
|
||||
audio (m4a, mp3, ogg, flac). Use --convert-
|
||||
subtitles lrc when embedding subtitles in
|
||||
audio files
|
||||
"lrc" in audio (m4a, mp3, ogg, flac)
|
||||
--no-embed-subs Do not embed subtitles (default)
|
||||
--embed-thumbnail Embed thumbnail in the video as cover art
|
||||
--no-embed-thumbnail Do not embed thumbnail (default)
|
||||
|
|
|
@ -1584,8 +1584,7 @@ def _alias_callback(option, opt_str, value, parser, opts, nargs):
|
|||
action='store_true', dest='embedsubtitles', default=False,
|
||||
help=(
|
||||
'Embed subtitles in downloaded media. '
|
||||
'Available for video (mp4, webm, mkv) and audio (m4a, mp3, ogg, flac). '
|
||||
'Use --convert-subtitles lrc when embedding subtitles in audio files'))
|
||||
'Available for video (mp4, webm, mkv) and "lrc" in audio (m4a, mp3, ogg, flac)'))
|
||||
postproc.add_option(
|
||||
'--no-embed-subs',
|
||||
action='store_false', dest='embedsubtitles',
|
||||
|
|
|
@ -91,8 +91,10 @@ def run(self, info):
|
|||
success = True
|
||||
if info['ext'] == 'mp3':
|
||||
# Method 1: Use mutagen
|
||||
# Prioritize mutagen over ffmpeg since ffmpeg messes up the lyrics data
|
||||
if mutagen:
|
||||
if not mutagen:
|
||||
self.to_screen('mutagen not was found. Falling back to ffmpeg. Lyrics may be corrupted')
|
||||
success = False
|
||||
else:
|
||||
try:
|
||||
self._report_run('mutagen', filename)
|
||||
audio = mutagen.id3.ID3(filename)
|
||||
|
@ -101,12 +103,11 @@ def run(self, info):
|
|||
encoding=mutagen.id3.Encoding.UTF8, mime=f'image/{thumbnail_ext}',
|
||||
type=mutagen.id3.PictureType.COVER_FRONT, desc='Cover (front)', data=thumbfile.read())
|
||||
audio.save()
|
||||
temp_filename = filename # Mutagen saves to the original file
|
||||
temp_filename = filename
|
||||
except Exception as err:
|
||||
self.report_warning(f'unable to embed using mutagen; {err}')
|
||||
success = False
|
||||
else:
|
||||
success = False
|
||||
|
||||
# Method 2: Use ffmpeg
|
||||
if not success:
|
||||
options = [
|
||||
|
|
|
@ -596,16 +596,16 @@ def __init__(self, downloader=None, already_have_subtitle=False):
|
|||
|
||||
@PostProcessor._restrict_to(images=False)
|
||||
def run(self, info):
|
||||
if info['ext'] not in self.SUPPORTED_EXTS:
|
||||
filename, ext = info['filepath'], info['ext']
|
||||
if ext not in self.SUPPORTED_EXTS:
|
||||
self.to_screen(f'Subtitles can only be embedded in {", ".join(self.SUPPORTED_EXTS)} files')
|
||||
return [], info
|
||||
|
||||
subtitles = info.get('requested_subtitles')
|
||||
if not subtitles:
|
||||
self.to_screen('There aren\'t any subtitles to embed')
|
||||
return [], info
|
||||
|
||||
filename = info['filepath']
|
||||
|
||||
# Disabled temporarily. There needs to be a way to override this
|
||||
# in case of duration actually mismatching in extractor
|
||||
# See: https://github.com/yt-dlp/yt-dlp/issues/1870, https://github.com/yt-dlp/yt-dlp/issues/1385
|
||||
|
@ -616,76 +616,84 @@ def run(self, info):
|
|||
return [], info
|
||||
'''
|
||||
|
||||
ext = info['ext']
|
||||
sub_langs, sub_names, sub_filenames = [], [], []
|
||||
webm_vtt_warn = False
|
||||
mp4_ass_warn = False
|
||||
warnings = set()
|
||||
|
||||
def warn_once(msg):
|
||||
if msg not in warnings:
|
||||
warnings.add(msg)
|
||||
self.report_warning(msg)
|
||||
|
||||
subtitles_to_embed = {}
|
||||
for lang, sub_info in subtitles.items():
|
||||
if not os.path.exists(sub_info.get('filepath', '')):
|
||||
self.report_warning(f'Skipping embedding {lang} subtitle because the file is missing')
|
||||
continue
|
||||
sub_ext = sub_info['ext']
|
||||
if sub_ext == 'json':
|
||||
self.report_warning('JSON subtitles cannot be embedded')
|
||||
elif ext != 'webm' or ext == 'webm' and sub_ext == 'vtt':
|
||||
sub_langs.append(lang)
|
||||
sub_names.append(sub_info.get('name'))
|
||||
sub_filenames.append(sub_info['filepath'])
|
||||
elif sub_info['ext'] == 'json':
|
||||
warn_once('JSON subtitles cannot be embedded')
|
||||
elif ext == 'webm' and sub_info['ext'] != 'vtt':
|
||||
warn_once('Only WebVTT subtitles can be embedded in webm files')
|
||||
elif ext in self.SUPPORTS_LYRICS and sub_info['ext'] != 'lrc':
|
||||
warn_once(f'Only lrc subtitles can be embedded in {ext} files')
|
||||
elif ext in self.SUPPORTS_LYRICS and not mutagen:
|
||||
raise PostProcessingError(
|
||||
f'[{self.PP_NAME}] module mutagen was not found. Please install using `python -m pip install mutagen`')
|
||||
else:
|
||||
if not webm_vtt_warn and ext == 'webm' and sub_ext != 'vtt':
|
||||
webm_vtt_warn = True
|
||||
self.report_warning('Only WebVTT subtitles can be embedded in webm files')
|
||||
if not mp4_ass_warn and ext == 'mp4' and sub_ext == 'ass':
|
||||
mp4_ass_warn = True
|
||||
self.report_warning('ASS subtitles cannot be properly embedded in mp4 files; expect issues')
|
||||
if ext == 'mp4' and sub_info['ext'] == 'ass':
|
||||
warn_once('ASS subtitles cannot be properly embedded in mp4 files; expect issues')
|
||||
subtitles_to_embed[lang] = sub_info
|
||||
|
||||
if not sub_langs:
|
||||
if not subtitles_to_embed:
|
||||
return [], info
|
||||
|
||||
input_files = [filename] + sub_filenames
|
||||
sub_files = [sub['filepath'] for sub in subtitles_to_embed.values()]
|
||||
files_to_delete = [] if self._already_have_subtitle else sub_files
|
||||
|
||||
if ext in self.SUPPORTS_LYRICS:
|
||||
self._embed_lyrics(subtitles_to_embed, info['filepath'], ext)
|
||||
return files_to_delete, info
|
||||
|
||||
opts = [
|
||||
*self.stream_copy_opts(ext=info['ext']),
|
||||
*self.stream_copy_opts(ext=ext),
|
||||
# Don't copy the existing subtitles, we may be running the
|
||||
# postprocessor a second time
|
||||
'-map', '-0:s',
|
||||
]
|
||||
for i, (lang, name) in enumerate(zip(sub_langs, sub_names)):
|
||||
opts.extend(['-map', '%d:0' % (i + 1)])
|
||||
lang_code = ISO639Utils.short2long(lang) or lang
|
||||
opts.extend(['-metadata:s:s:%d' % i, 'language=%s' % lang_code])
|
||||
if name:
|
||||
opts.extend(['-metadata:s:s:%d' % i, 'handler_name=%s' % name,
|
||||
'-metadata:s:s:%d' % i, 'title=%s' % name])
|
||||
for i, (lang, sub) in enumerate(subtitles_to_embed.items()):
|
||||
lang = ISO639Utils.short2long(lang) or lang
|
||||
opts.extend(['-map', f'{i + 1}:0', f'-metadata:s:s:{i}', f'language={lang}'])
|
||||
if name := sub['name']:
|
||||
opts.extend([f'-metadata:s:s:{i}', f'handler_name={name}',
|
||||
f'-metadata:s:s:{i}', f'title={name}'])
|
||||
|
||||
temp_filename = prepend_extension(filename, 'temp')
|
||||
self.to_screen('Embedding subtitles in "%s"' % filename)
|
||||
if info['ext'] in self.SUPPORTS_LYRICS:
|
||||
self.embed_lyrics(info['filepath'], sub_dict=info['requested_subtitles'])
|
||||
else:
|
||||
self.run_ffmpeg_multiple_files(input_files, temp_filename, opts)
|
||||
os.replace(temp_filename, filename)
|
||||
self.to_screen(f'Embedding subtitles in "{filename}"')
|
||||
self.run_ffmpeg_multiple_files([filename, *sub_files], temp_filename, opts)
|
||||
os.replace(temp_filename, filename)
|
||||
|
||||
files_to_delete = [] if self._already_have_subtitle else sub_filenames
|
||||
return files_to_delete, info
|
||||
|
||||
def embed_lyrics(self, audio_file, sub_dict):
|
||||
if not all(sub['ext'] == 'lrc' for sub in sub_dict.values()):
|
||||
raise PostProcessingError('LRC subtitles required. Use "--convert-subs lrc" to convert')
|
||||
if len(sub_dict) > 1:
|
||||
self.report_warning('More than one subtitle file found. Your media player will likely be unable to display all of them.')
|
||||
def _embed_lyrics(self, subtitles, filename, ext):
|
||||
assert mutagen and ext in self.SUPPORTS_LYRICS and all(sub['ext'] == 'lrc' for sub in subtitles.values())
|
||||
self.to_screen(f'Embedding lyrics in "{filename}"')
|
||||
if len(subtitles) > 1:
|
||||
self.report_warning(
|
||||
f'Your media player may be unable to display multiple subtitles in {ext}')
|
||||
|
||||
lyrics_list = [sub['data'] for sub in sub_dict.values()]
|
||||
if audio_file.endswith('.mp3'):
|
||||
audio = mutagen.id3.ID3(audio_file)
|
||||
for lyrics in lyrics_list:
|
||||
audio.add(mutagen.id3.USLT(encoding=mutagen.id3.Encoding.UTF8, lang='und', text=lyrics))
|
||||
audio.save()
|
||||
for lang, sub in subtitles.items():
|
||||
if not sub.get('data'):
|
||||
with open(sub['filepath'], encoding='utf-8') as f:
|
||||
sub['data'] = f.read()
|
||||
|
||||
if ext == 'mp3':
|
||||
metadata = mutagen.id3.ID3(filename)
|
||||
for lang, sub in subtitles.items():
|
||||
metadata.add(mutagen.id3.USLT(
|
||||
encoding=mutagen.id3.Encoding.UTF8,
|
||||
lang=ISO639Utils.short2long(lang) or 'und',
|
||||
text=sub['data']))
|
||||
else:
|
||||
metadata = mutagen.File(audio_file)
|
||||
metadata['©lyr' if audio_file.endswith('.m4a') else 'lyrics'] = lyrics_list
|
||||
metadata.save()
|
||||
metadata = mutagen.File(filename)
|
||||
metadata['©lyr' if ext == 'm4a' else 'lyrics'] = [sub['data'] for sub in subtitles.values()]
|
||||
metadata.save()
|
||||
|
||||
|
||||
class FFmpegMetadataPP(FFmpegPostProcessor):
|
||||
|
|
|
@ -3733,6 +3733,8 @@ class ISO639Utils:
|
|||
@classmethod
|
||||
def short2long(cls, code):
|
||||
"""Convert language code from ISO 639-1 to ISO 639-2/T"""
|
||||
if code in cls._lang_map.values():
|
||||
return code
|
||||
return cls._lang_map.get(code[:2])
|
||||
|
||||
@classmethod
|
||||
|
|
Loading…
Reference in a new issue