1
0
Fork 0
mirror of https://github.com/yt-dlp/yt-dlp.git synced 2025-03-09 12:50:23 -05:00
This commit is contained in:
pukkandan 2024-02-20 09:03:28 +05:30
parent 54792c9da8
commit b18cc9c633
No known key found for this signature in database
GPG key ID: 7EEE9E1E817D0A39
5 changed files with 70 additions and 62 deletions

View file

@ -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)

View file

@ -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',

View file

@ -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 = [

View file

@ -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):

View file

@ -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