aboutsummaryrefslogtreecommitdiffstats
path: root/hypervideo_dl/postprocessor
diff options
context:
space:
mode:
Diffstat (limited to 'hypervideo_dl/postprocessor')
-rw-r--r--hypervideo_dl/postprocessor/__init__.py5
-rw-r--r--hypervideo_dl/postprocessor/common.py13
-rw-r--r--hypervideo_dl/postprocessor/embedthumbnail.py6
-rw-r--r--hypervideo_dl/postprocessor/ffmpeg.py29
-rw-r--r--hypervideo_dl/postprocessor/metadataparser.py4
-rw-r--r--hypervideo_dl/postprocessor/modify_chapters.py1
6 files changed, 37 insertions, 21 deletions
diff --git a/hypervideo_dl/postprocessor/__init__.py b/hypervideo_dl/postprocessor/__init__.py
index f168be4..bfe9df7 100644
--- a/hypervideo_dl/postprocessor/__init__.py
+++ b/hypervideo_dl/postprocessor/__init__.py
@@ -33,14 +33,15 @@ from .movefilesafterdownload import MoveFilesAfterDownloadPP
from .sponskrub import SponSkrubPP
from .sponsorblock import SponsorBlockPP
from .xattrpp import XAttrMetadataPP
-from ..utils import load_plugins
+from ..plugins import load_plugins
-_PLUGIN_CLASSES = load_plugins('postprocessor', 'PP', globals())
+_PLUGIN_CLASSES = load_plugins('postprocessor', 'PP')
def get_postprocessor(key):
return globals()[key + 'PP']
+globals().update(_PLUGIN_CLASSES)
__all__ = [name for name in globals().keys() if name.endswith('PP')]
__all__.extend(('PostProcessor', 'FFmpegPostProcessor'))
diff --git a/hypervideo_dl/postprocessor/common.py b/hypervideo_dl/postprocessor/common.py
index c3fca35..9a0aa6f 100644
--- a/hypervideo_dl/postprocessor/common.py
+++ b/hypervideo_dl/postprocessor/common.py
@@ -1,16 +1,15 @@
import functools
import json
import os
-import urllib.error
+from ..networking import Request
+from ..networking.exceptions import HTTPError, network_exceptions
from ..utils import (
PostProcessingError,
RetryManager,
_configuration_args,
deprecation_warning,
encodeFilename,
- network_exceptions,
- sanitized_Request,
)
@@ -187,7 +186,7 @@ class PostProcessor(metaclass=PostProcessorMetaClass):
tmpl = progress_template.get('postprocess')
if tmpl:
self._downloader.to_screen(
- self._downloader.evaluate_outtmpl(tmpl, progress_dict), skip_eol=True, quiet=False)
+ self._downloader.evaluate_outtmpl(tmpl, progress_dict), quiet=False)
self._downloader.to_console_title(self._downloader.evaluate_outtmpl(
progress_template.get('postprocess-title') or 'hypervideo %(progress._default_template)s',
@@ -203,13 +202,13 @@ class PostProcessor(metaclass=PostProcessorMetaClass):
self.write_debug(f'{self.PP_NAME} query: {url}')
for retry in RetryManager(self.get_param('extractor_retries', 3), self._retry_download):
try:
- rsp = self._downloader.urlopen(sanitized_Request(url))
+ rsp = self._downloader.urlopen(Request(url))
except network_exceptions as e:
- if isinstance(e, urllib.error.HTTPError) and e.code in expected_http_errors:
+ if isinstance(e, HTTPError) and e.status in expected_http_errors:
return None
retry.error = PostProcessingError(f'Unable to communicate with {self.PP_NAME} API: {e}')
continue
- return json.loads(rsp.read().decode(rsp.info().get_param('charset') or 'utf-8'))
+ return json.loads(rsp.read().decode(rsp.headers.get_param('charset') or 'utf-8'))
class AudioConversionError(PostProcessingError): # Deprecated
diff --git a/hypervideo_dl/postprocessor/embedthumbnail.py b/hypervideo_dl/postprocessor/embedthumbnail.py
index 7cd3952..707ec76 100644
--- a/hypervideo_dl/postprocessor/embedthumbnail.py
+++ b/hypervideo_dl/postprocessor/embedthumbnail.py
@@ -107,14 +107,14 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
options.extend(['-map', '-0:%d' % old_stream])
new_stream -= 1
options.extend([
- '-attach', thumbnail_filename,
+ '-attach', self._ffmpeg_filename_argument(thumbnail_filename),
'-metadata:s:%d' % new_stream, 'mimetype=%s' % mimetype,
'-metadata:s:%d' % new_stream, 'filename=cover.%s' % thumbnail_ext])
self._report_run('ffmpeg', filename)
self.run_ffmpeg(filename, temp_filename, options)
- elif info['ext'] in ['m4a', 'mp4', 'mov']:
+ elif info['ext'] in ['m4a', 'mp4', 'm4v', 'mov']:
prefer_atomicparsley = 'embed-thumbnail-atomicparsley' in self.get_param('compat_opts', [])
# Method 1: Use mutagen
if not mutagen or prefer_atomicparsley:
@@ -213,7 +213,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
temp_filename = filename
else:
- raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov')
+ raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/m4v/mov')
if success and temp_filename != filename:
os.replace(temp_filename, filename)
diff --git a/hypervideo_dl/postprocessor/ffmpeg.py b/hypervideo_dl/postprocessor/ffmpeg.py
index 0471594..5bd0dbd 100644
--- a/hypervideo_dl/postprocessor/ffmpeg.py
+++ b/hypervideo_dl/postprocessor/ffmpeg.py
@@ -44,6 +44,7 @@ EXT_TO_OUT_FORMATS = {
'ts': 'mpegts',
'wma': 'asf',
'wmv': 'asf',
+ 'weba': 'webm',
'vtt': 'webvtt',
}
ACODECS = {
@@ -301,6 +302,11 @@ class FFmpegPostProcessor(PostProcessor):
None)
return num, len(streams)
+ def _fixup_chapters(self, info):
+ last_chapter = traverse_obj(info, ('chapters', -1))
+ if last_chapter and not last_chapter.get('end_time'):
+ last_chapter['end_time'] = self._get_real_video_duration(info['filepath'])
+
def _get_real_video_duration(self, filepath, fatal=True):
try:
duration = float_or_none(
@@ -407,7 +413,7 @@ class FFmpegPostProcessor(PostProcessor):
"""
concat_file = f'{out_file}.concat'
self.write_debug(f'Writing concat spec to {concat_file}')
- with open(concat_file, 'wt', encoding='utf-8') as f:
+ with open(concat_file, 'w', encoding='utf-8') as f:
f.writelines(self._concat_spec(in_files, concat_opts))
out_flags = list(self.stream_copy_opts(ext=determine_ext(out_file)))
@@ -507,8 +513,7 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor):
if acodec != 'copy':
more_opts = self._quality_args(acodec)
- # not os.path.splitext, since the latter does not work on unicode in all setups
- temp_path = new_path = f'{path.rpartition(".")[0]}.{extension}'
+ temp_path = new_path = replace_extension(path, extension, information['ext'])
if new_path == path:
if acodec == 'copy':
@@ -538,7 +543,10 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor):
class FFmpegVideoConvertorPP(FFmpegPostProcessor):
- SUPPORTED_EXTS = (*MEDIA_EXTENSIONS.common_video, *sorted(MEDIA_EXTENSIONS.common_audio + ('aac', 'vorbis')))
+ SUPPORTED_EXTS = (
+ *sorted((*MEDIA_EXTENSIONS.common_video, 'gif')),
+ *sorted((*MEDIA_EXTENSIONS.common_audio, 'aac', 'vorbis')),
+ )
FORMAT_RE = create_mapping_re(SUPPORTED_EXTS)
_ACTION = 'converting'
@@ -675,6 +683,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
@PostProcessor._restrict_to(images=False)
def run(self, info):
+ self._fixup_chapters(info)
filename, metadata_filename = info['filepath'], None
files_to_delete, options = [], []
if self._add_chapters and info.get('chapters'):
@@ -708,7 +717,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
@staticmethod
def _get_chapter_opts(chapters, metadata_filename):
- with open(metadata_filename, 'wt', encoding='utf-8') as f:
+ with open(metadata_filename, 'w', encoding='utf-8') as f:
def ffmpeg_escape(text):
return re.sub(r'([\\=;#\n])', r'\\\1', text)
@@ -800,7 +809,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
new_stream -= 1
yield (
- '-attach', infofn,
+ '-attach', self._ffmpeg_filename_argument(infofn),
f'-metadata:s:{new_stream}', 'mimetype=application/json',
f'-metadata:s:{new_stream}', 'filename=info.json',
)
@@ -889,8 +898,11 @@ class FFmpegFixupM3u8PP(FFmpegFixupPostProcessor):
@PostProcessor._restrict_to(images=False)
def run(self, info):
if all(self._needs_fixup(info)):
+ args = ['-f', 'mp4']
+ if self.get_audio_codec(info['filepath']) == 'aac':
+ args.extend(['-bsf:a', 'aac_adtstoasc'])
self._fixup('Fixing MPEG-TS in MP4 container', info['filepath'], [
- *self.stream_copy_opts(), '-f', 'mp4', '-bsf:a', 'aac_adtstoasc'])
+ *self.stream_copy_opts(), *args])
return [], info
@@ -978,7 +990,7 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
with open(dfxp_file, 'rb') as f:
srt_data = dfxp2srt(f.read())
- with open(srt_file, 'wt', encoding='utf-8') as f:
+ with open(srt_file, 'w', encoding='utf-8') as f:
f.write(srt_data)
old_file = srt_file
@@ -1037,6 +1049,7 @@ class FFmpegSplitChaptersPP(FFmpegPostProcessor):
@PostProcessor._restrict_to(images=False)
def run(self, info):
+ self._fixup_chapters(info)
chapters = info.get('chapters') or []
if not chapters:
self.to_screen('Chapter information is unavailable')
diff --git a/hypervideo_dl/postprocessor/metadataparser.py b/hypervideo_dl/postprocessor/metadataparser.py
index 381182b..509dccb 100644
--- a/hypervideo_dl/postprocessor/metadataparser.py
+++ b/hypervideo_dl/postprocessor/metadataparser.py
@@ -1,7 +1,7 @@
import re
from .common import PostProcessor
-from ..utils import Namespace, filter_dict
+from ..utils import Namespace, filter_dict, function_with_repr
class MetadataParserPP(PostProcessor):
@@ -60,6 +60,7 @@ class MetadataParserPP(PostProcessor):
f(info)
return [], info
+ @function_with_repr
def interpretter(self, inp, out):
def f(info):
data_to_parse = self._downloader.evaluate_outtmpl(template, info)
@@ -76,6 +77,7 @@ class MetadataParserPP(PostProcessor):
out_re = re.compile(self.format_to_regex(out))
return f
+ @function_with_repr
def replacer(self, field, search, replace):
def f(info):
val = info.get(field)
diff --git a/hypervideo_dl/postprocessor/modify_chapters.py b/hypervideo_dl/postprocessor/modify_chapters.py
index a745b45..f521986 100644
--- a/hypervideo_dl/postprocessor/modify_chapters.py
+++ b/hypervideo_dl/postprocessor/modify_chapters.py
@@ -23,6 +23,7 @@ class ModifyChaptersPP(FFmpegPostProcessor):
@PostProcessor._restrict_to(images=False)
def run(self, info):
+ self._fixup_chapters(info)
# Chapters must be preserved intact when downloading multiple formats of the same video.
chapters, sponsor_chapters = self._mark_chapters_to_remove(
copy.deepcopy(info.get('chapters')) or [],