diff --git a/README.md b/README.md index 7be3266ea5..8cd9d892f6 100644 --- a/README.md +++ b/README.md @@ -241,8 +241,6 @@ The following provide support for impersonating browser requests. This may be re ### Deprecated -* [**avconv** and **avprobe**](https://www.libav.org) - Now **deprecated** alternative to ffmpeg. License [depends on the build](https://libav.org/legal) -* [**sponskrub**](https://github.com/faissaloo/SponSkrub) - For using the now **deprecated** [sponskrub options](#sponskrub-options). Licensed under [GPLv3+](https://github.com/faissaloo/SponSkrub/blob/master/LICENCE.md) * [**rtmpdump**](http://rtmpdump.mplayerhq.hu) - For downloading `rtmp` streams. ffmpeg can be used instead with `--downloader ffmpeg`. Licensed under [GPLv2+](http://rtmpdump.mplayerhq.hu) * [**mplayer**](http://mplayerhq.hu/design7/info.html) or [**mpv**](https://mpv.io) - For downloading `rstp`/`mms` streams. ffmpeg can be used instead with `--downloader ffmpeg`. Licensed under [GPLv2+](https://github.com/mpv-player/mpv/blob/master/Copyright) @@ -2363,10 +2361,6 @@ While these options still work, their use is not recommended since there are oth --hls-prefer-ffmpeg --downloader "m3u8:ffmpeg" --list-formats-old --compat-options list-formats (Alias: --no-list-formats-as-table) --list-formats-as-table --compat-options -list-formats [Default] (Alias: --no-list-formats-old) - --youtube-skip-dash-manifest --extractor-args "youtube:skip=dash" (Alias: --no-youtube-include-dash-manifest) - --youtube-skip-hls-manifest --extractor-args "youtube:skip=hls" (Alias: --no-youtube-include-hls-manifest) - --youtube-include-dash-manifest Default (Alias: --no-youtube-skip-dash-manifest) - --youtube-include-hls-manifest Default (Alias: --no-youtube-skip-hls-manifest) --geo-bypass --xff "default" --no-geo-bypass --xff "never" --geo-bypass-country CODE --xff CODE @@ -2377,18 +2371,13 @@ These options are not intended to be used by the end-user --test Download only part of video for testing extractors --load-pages Load pages dumped by --write-pages - --youtube-print-sig-code For testing youtube signatures --allow-unplayable-formats List unplayable formats also --no-allow-unplayable-formats Default #### Old aliases These are aliases that are no longer documented for various reasons - --avconv-location --ffmpeg-location --clean-infojson --clean-info-json - --cn-verification-proxy URL --geo-verification-proxy URL - --dump-headers --print-traffic - --dump-intermediate-pages --dump-pages --force-write-download-archive --force-write-archive --no-clean-infojson --no-clean-info-json --no-split-tracks --no-split-chapters @@ -2402,7 +2391,7 @@ These are aliases that are no longer documented for various reasons --yes-overwrites --force-overwrites #### Sponskrub Options -Support for [SponSkrub](https://github.com/faissaloo/SponSkrub) has been deprecated in favor of the `--sponsorblock` options +Support for [SponSkrub](https://github.com/faissaloo/SponSkrub) has been removed in favor of the `--sponsorblock` options --sponskrub --sponsorblock-mark all --no-sponskrub --no-sponsorblock @@ -2424,6 +2413,17 @@ These options may no longer work as intended --no-include-ads Default --write-annotations No supported site has annotations now --no-write-annotations Default + --avconv-location Removed alias for --ffmpeg-location + --cn-verification-proxy URL Removed alias for --geo-verification-proxy URL + --dump-headers Removed alias for --print-traffic + --dump-intermediate-pages Removed alias for --dump-pages + --youtube-skip-dash-manifest Removed alias for --extractor-args "youtube:skip=dash" (Alias: --no-youtube-include-dash-manifest) + --youtube-skip-hls-manifest Removed alias for --extractor-args "youtube:skip=hls" (Alias: --no-youtube-include-hls-manifest) + --youtube-include-dash-manifest Default (Alias: --no-youtube-skip-dash-manifest) + --youtube-include-hls-manifest Default (Alias: --no-youtube-skip-hls-manifest) + --youtube-print-sig-code Removed testing functionality + --dump-user-agent No longer supported + --xattr-set-filesize No longer supported --compat-options seperate-video-versions No longer needed --compat-options no-youtube-prefer-utc-upload-date No longer supported diff --git a/test/parameters.json b/test/parameters.json index 8789ce14b3..d08748a500 100644 --- a/test/parameters.json +++ b/test/parameters.json @@ -36,7 +36,6 @@ "verbose": true, "writedescription": false, "writeinfojson": true, - "writeannotations": false, "writelink": false, "writeurllink": false, "writewebloclink": false, diff --git a/test/test_websockets.py b/test/test_websockets.py index dead5fe5c5..167f67daa7 100644 --- a/test/test_websockets.py +++ b/test/test_websockets.py @@ -20,7 +20,7 @@ import random import ssl import threading -from yt_dlp import socks, traverse_obj +from yt_dlp import socks from yt_dlp.cookies import YoutubeDLCookieJar from yt_dlp.dependencies import websockets from yt_dlp.networking import Request @@ -32,6 +32,7 @@ from yt_dlp.networking.exceptions import ( SSLError, TransportError, ) +from yt_dlp.utils.traversal import traverse_obj from yt_dlp.utils.networking import HTTPHeaderDict TEST_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/test/test_write_annotations.py.disabled b/test/test_write_annotations.py.disabled deleted file mode 100644 index c7cf199f6c..0000000000 --- a/test/test_write_annotations.py.disabled +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 - -# Allow direct execution -import os -import sys -import unittest - -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - - -import xml.etree.ElementTree - -import yt_dlp.extractor -import yt_dlp.YoutubeDL -from test.helper import get_params, is_download_test, try_rm - - -class YoutubeDL(yt_dlp.YoutubeDL): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.to_stderr = self.to_screen - - -params = get_params({ - 'writeannotations': True, - 'skip_download': True, - 'writeinfojson': False, - 'format': 'flv', -}) - - -TEST_ID = 'gr51aVj-mLg' -ANNOTATIONS_FILE = TEST_ID + '.annotations.xml' -EXPECTED_ANNOTATIONS = ['Speech bubble', 'Note', 'Title', 'Spotlight', 'Label'] - - -@is_download_test -class TestAnnotations(unittest.TestCase): - def setUp(self): - # Clear old files - self.tearDown() - - def test_info_json(self): - expected = list(EXPECTED_ANNOTATIONS) # Two annotations could have the same text. - ie = yt_dlp.extractor.YoutubeIE() - ydl = YoutubeDL(params) - ydl.add_info_extractor(ie) - ydl.download([TEST_ID]) - self.assertTrue(os.path.exists(ANNOTATIONS_FILE)) - annoxml = None - with open(ANNOTATIONS_FILE, encoding='utf-8') as annof: - annoxml = xml.etree.ElementTree.parse(annof) - self.assertTrue(annoxml is not None, 'Failed to parse annotations XML') - root = annoxml.getroot() - self.assertEqual(root.tag, 'document') - annotationsTag = root.find('annotations') - self.assertEqual(annotationsTag.tag, 'annotations') - annotations = annotationsTag.findall('annotation') - - # Not all the annotations have TEXT children and the annotations are returned unsorted. - for a in annotations: - self.assertEqual(a.tag, 'annotation') - if a.get('type') == 'text': - textTag = a.find('TEXT') - text = textTag.text - self.assertTrue(text in expected) # assertIn only added in python 2.7 - # remove the first occurrence, there could be more than one annotation with the same text - expected.remove(text) - # We should have seen (and removed) all the expected annotation texts. - self.assertEqual(len(expected), 0, 'Not all expected annotations were found.') - - def tearDown(self): - try_rm(ANNOTATIONS_FILE) - - -if __name__ == '__main__': - unittest.main() diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 08a1dc493d..3b41a15196 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -304,7 +304,6 @@ class YoutubeDL: clean_infojson: Remove internal metadata from the infojson getcomments: Extract video comments. This will not be written to disk unless writeinfojson is also given - writeannotations: Write the video annotations to a .annotations.xml file writethumbnail: Write the thumbnail image to a file allow_playlist_files: Whether to write playlists' description, infojson etc also to disk when using the 'write*' options @@ -511,11 +510,11 @@ class YoutubeDL: the downloader (see yt_dlp/downloader/common.py): nopart, updatetime, buffersize, ratelimit, throttledratelimit, min_filesize, max_filesize, test, noresizebuffer, retries, file_access_retries, fragment_retries, - continuedl, xattr_set_filesize, hls_use_mpegts, http_chunk_size, - external_downloader_args, concurrent_fragment_downloads, progress_delta. + continuedl, hls_use_mpegts, http_chunk_size, external_downloader_args, + concurrent_fragment_downloads, progress_delta. The following options are used by the post processors: - ffmpeg_location: Location of the ffmpeg/avconv binary; either the path + ffmpeg_location: Location of the ffmpeg binary; either the path to the binary or its containing directory. postprocessor_args: A dictionary of postprocessor/executable keys (in lower case) and a list of additional command-line arguments for the @@ -566,32 +565,14 @@ class YoutubeDL: allsubtitles: - Use subtitleslangs = ['all'] Downloads all the subtitles of the video (requires writesubtitles or writeautomaticsub) - include_ads: - Doesn't work - Download ads as well - call_home: - Not implemented - Boolean, true if we are allowed to contact the - yt-dlp servers for debugging. post_hooks: - Register a custom postprocessor A list of functions that get called as the final step for each video file, after all postprocessors have been called. The filename will be passed as the only argument. hls_prefer_native: - Use external_downloader = {'m3u8': 'native'} or {'m3u8': 'ffmpeg'}. - Use the native HLS downloader instead of ffmpeg/avconv - if True, otherwise use ffmpeg/avconv if False, otherwise + Use the native HLS downloader instead of ffmpeg + if True, otherwise use ffmpeg if False, otherwise use downloader suggested by extractor if None. - prefer_ffmpeg: - avconv support is deprecated - If False, use avconv instead of ffmpeg if both are available, - otherwise prefer ffmpeg. - youtube_include_dash_manifest: - Use extractor_args - If True (default), DASH manifests and related - data will be downloaded and processed by extractor. - You can reduce network I/O by disabling it if you don't - care about DASH. (only for youtube) - youtube_include_hls_manifest: - Use extractor_args - If True (default), HLS manifests and related - data will be downloaded and processed by extractor. - You can reduce network I/O by disabling it if you don't - care about HLS. (only for youtube) no_color: Same as `color='no_color'` no_overwrites: Same as `overwrites=False` """ @@ -750,10 +731,6 @@ class YoutubeDL: return True return False - if check_deprecated('cn_verification_proxy', '--cn-verification-proxy', '--geo-verification-proxy'): - if self.params.get('geo_verification_proxy') is None: - self.params['geo_verification_proxy'] = self.params['cn_verification_proxy'] - check_deprecated('useid', '--id', '-o "%(id)s.%(ext)s"') for msg in self.params.get('_warnings', []): @@ -3335,28 +3312,6 @@ class YoutubeDL: elif _infojson_written is None: return - # Note: Annotations are deprecated - annofn = None - if self.params.get('writeannotations', False): - annofn = self.prepare_filename(info_dict, 'annotation') - if annofn: - if not self._ensure_dir_exists(annofn): - return - if not self.params.get('overwrites', True) and os.path.exists(annofn): - self.to_screen('[info] Video annotations are already present') - elif not info_dict.get('annotations'): - self.report_warning('There are no annotations to write.') - else: - try: - self.to_screen('[info] Writing video annotations to: ' + annofn) - with open(annofn, 'w', encoding='utf-8') as annofile: - annofile.write(info_dict['annotations']) - except (KeyError, TypeError): - self.report_warning('There are no annotations to write.') - except OSError: - self.report_error('Cannot write annotations file: ' + annofn) - return - # Write internet shortcut files def _write_link_file(link_type): url = try_get(info_dict['webpage_url'], iri_to_uri) diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 25f8d93f8b..09c022fa0e 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -59,11 +59,9 @@ from .utils import ( render_table, setproctitle, shell_quote, - traverse_obj, variadic, write_string, ) -from .utils.networking import std_headers from .utils._utils import _UnsafeExtensionError from .YoutubeDL import YoutubeDL @@ -523,7 +521,6 @@ def validate_options(opts): if report_args_compat('post-processor', opts.postprocessor_args, 'default-compat', 'default'): opts.postprocessor_args['default'] = opts.postprocessor_args.pop('default-compat') - opts.postprocessor_args.setdefault('sponskrub', []) def report_conflict(arg1, opt1, arg2='--allow-unplayable-formats', opt2='allow_unplayable_formats', val1=NO_DEFAULT, val2=NO_DEFAULT, default=False): @@ -548,11 +545,6 @@ def validate_options(opts): '"--exec before_dl:"', 'exec_cmd', val2=opts.exec_cmd.get('before_dl')) report_conflict('--id', 'useid', '--output', 'outtmpl', val2=opts.outtmpl.get('default')) report_conflict('--remux-video', 'remuxvideo', '--recode-video', 'recodevideo') - report_conflict('--sponskrub', 'sponskrub', '--remove-chapters', 'remove_chapters') - report_conflict('--sponskrub', 'sponskrub', '--sponsorblock-mark', 'sponsorblock_mark') - report_conflict('--sponskrub', 'sponskrub', '--sponsorblock-remove', 'sponsorblock_remove') - report_conflict('--sponskrub-cut', 'sponskrub_cut', '--split-chapter', 'split_chapters', - val1=opts.sponskrub and opts.sponskrub_cut) # Conflicts with --allow-unplayable-formats report_conflict('--embed-metadata', 'addmetadata') @@ -565,23 +557,15 @@ def validate_options(opts): report_conflict('--recode-video', 'recodevideo') report_conflict('--remove-chapters', 'remove_chapters', default=[]) report_conflict('--remux-video', 'remuxvideo') - report_conflict('--sponskrub', 'sponskrub') report_conflict('--sponsorblock-remove', 'sponsorblock_remove', default=set()) report_conflict('--xattrs', 'xattrs') - # Fully deprecated options - def report_deprecation(val, old, new=None): - if not val: - return + if hasattr(opts, '_deprecated_options'): deprecation_warnings.append( - f'{old} is deprecated and may be removed in a future version. Use {new} instead' if new - else f'{old} is deprecated and may not work as expected') - - report_deprecation(opts.sponskrub, '--sponskrub', '--sponsorblock-mark or --sponsorblock-remove') - report_deprecation(not opts.prefer_ffmpeg, '--prefer-avconv', 'ffmpeg') - # report_deprecation(opts.include_ads, '--include-ads') # We may re-implement this in future - # report_deprecation(opts.call_home, '--call-home') # We may re-implement this in future - # report_deprecation(opts.writeannotations, '--write-annotations') # It's just that no website has it + f'The following options have been deprecated: {", ".join(opts._deprecated_options)}\n' + 'Please remove them from your command/configuration to avoid future errors.\n' + 'See https://github.com/yt-dlp/yt-dlp/issues/14198 for more details') + del opts._deprecated_options # Dependent options opts.date = DateRange.day(opts.date) if opts.date else DateRange(opts.dateafter, opts.datebefore) @@ -712,21 +696,6 @@ def get_postprocessors(opts): 'add_metadata': opts.addmetadata, 'add_infojson': opts.embed_infojson, } - # Deprecated - # This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment - # but must be below EmbedSubtitle and FFmpegMetadata - # See https://github.com/yt-dlp/yt-dlp/issues/204 , https://github.com/faissaloo/SponSkrub/issues/29 - # If opts.sponskrub is None, sponskrub is used, but it silently fails if the executable can't be found - if opts.sponskrub is not False: - yield { - 'key': 'SponSkrub', - 'path': opts.sponskrub_path, - 'args': opts.sponskrub_args, - 'cut': opts.sponskrub_cut, - 'force': opts.sponskrub_force, - 'ignoreerror': opts.sponskrub is None, - '_from_cli': True, - } if opts.embedthumbnail: yield { 'key': 'EmbedThumbnail', @@ -885,7 +854,6 @@ def parse_options(argv=None): 'nopart': opts.nopart, 'updatetime': opts.updatetime, 'writedescription': opts.writedescription, - 'writeannotations': opts.writeannotations, 'writeinfojson': opts.writeinfojson, 'allow_playlist_files': opts.allow_playlist_files, 'clean_infojson': opts.clean_infojson, @@ -919,7 +887,6 @@ def parse_options(argv=None): 'max_views': opts.max_views, 'daterange': opts.date, 'cachedir': opts.cachedir, - 'youtube_print_sig_code': opts.youtube_print_sig_code, 'age_limit': opts.age_limit, 'download_archive': opts.download_archive, 'break_on_existing': opts.break_on_existing, @@ -937,13 +904,9 @@ def parse_options(argv=None): 'socket_timeout': opts.socket_timeout, 'bidi_workaround': opts.bidi_workaround, 'debug_printtraffic': opts.debug_printtraffic, - 'prefer_ffmpeg': opts.prefer_ffmpeg, - 'include_ads': opts.include_ads, 'default_search': opts.default_search, 'dynamic_mpd': opts.dynamic_mpd, 'extractor_args': opts.extractor_args, - 'youtube_include_dash_manifest': opts.youtube_include_dash_manifest, - 'youtube_include_hls_manifest': opts.youtube_include_hls_manifest, 'encoding': opts.encoding, 'extract_flat': opts.extract_flat, 'live_from_start': opts.live_from_start, @@ -955,7 +918,6 @@ def parse_options(argv=None): 'fixup': opts.fixup, 'source_address': opts.source_address, 'impersonate': opts.impersonate, - 'call_home': opts.call_home, 'sleep_interval_requests': opts.sleep_interval_requests, 'sleep_interval': opts.sleep_interval, 'max_sleep_interval': opts.max_sleep_interval, @@ -965,7 +927,6 @@ def parse_options(argv=None): 'force_keyframes_at_cuts': opts.force_keyframes_at_cuts, 'list_thumbnails': opts.list_thumbnails, 'playlist_items': opts.playlist_items, - 'xattr_set_filesize': opts.xattr_set_filesize, 'match_filter': opts.match_filter, 'color': opts.color, 'ffmpeg_location': opts.ffmpeg_location, @@ -974,7 +935,6 @@ def parse_options(argv=None): 'hls_split_discontinuity': opts.hls_split_discontinuity, 'external_downloader_args': opts.external_downloader_args, 'postprocessor_args': opts.postprocessor_args, - 'cn_verification_proxy': opts.cn_verification_proxy, 'geo_verification_proxy': opts.geo_verification_proxy, 'geo_bypass': opts.geo_bypass, 'geo_bypass_country': opts.geo_bypass_country, @@ -992,12 +952,6 @@ def _real_main(argv=None): parser, opts, all_urls, ydl_opts = parse_options(argv) - # Dump user agent - if opts.dump_user_agent: - ua = traverse_obj(opts.headers, 'User-Agent', casesense=False, default=std_headers['User-Agent']) - write_string(f'{ua}\n', out=sys.stdout) - return - if print_extractor_information(opts, all_urls): return diff --git a/yt_dlp/downloader/common.py b/yt_dlp/downloader/common.py index 3dd86a971d..122c479562 100644 --- a/yt_dlp/downloader/common.py +++ b/yt_dlp/downloader/common.py @@ -62,7 +62,6 @@ class FileDownloader: test: Download only first bytes to test the downloader. min_filesize: Skip files smaller than this size max_filesize: Skip files larger than this size - xattr_set_filesize: Set ytdl.filesize user xattribute with expected size. progress_delta: The minimum time between progress output, in seconds external_downloader_args: A dictionary of downloader keys (in lower case) and a list of additional command-line arguments for the diff --git a/yt_dlp/downloader/external.py b/yt_dlp/downloader/external.py index 65ed83991b..3b8fd27bc7 100644 --- a/yt_dlp/downloader/external.py +++ b/yt_dlp/downloader/external.py @@ -563,7 +563,7 @@ class FFmpegFD(ExternalFD): f'{cookie.name}={cookie.value}; path={cookie.path}; domain={cookie.domain};\r\n' for cookie in cookies)]) if fmt.get('http_headers') and is_http: - # Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg/avconv: + # Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg: # [http @ 00000000003d2fa0] No trailing CRLF found in HTTP header. args.extend(['-headers', ''.join(f'{key}: {val}\r\n' for key, val in fmt['http_headers'].items())]) @@ -654,10 +654,6 @@ class FFmpegFD(ExternalFD): return retval -class AVconvFD(FFmpegFD): - pass - - _BY_NAME = { klass.get_basename(): klass for name, klass in globals().items() diff --git a/yt_dlp/downloader/http.py b/yt_dlp/downloader/http.py index c388deb7ea..6dcf7e7b69 100644 --- a/yt_dlp/downloader/http.py +++ b/yt_dlp/downloader/http.py @@ -13,12 +13,9 @@ from ..utils import ( ContentTooShortError, RetryManager, ThrottledDownload, - XAttrMetadataError, - XAttrUnavailableError, int_or_none, parse_http_range, try_call, - write_xattr, ) from ..utils.networking import HTTPHeaderDict @@ -273,12 +270,6 @@ class HttpFD(FileDownloader): self.report_error(f'unable to open for writing: {err}') return False - if self.params.get('xattr_set_filesize', False) and data_len is not None: - try: - write_xattr(ctx.tmpfilename, 'user.ytdl.filesize', str(data_len).encode()) - except (XAttrUnavailableError, XAttrMetadataError) as err: - self.report_error(f'unable to set filesize xattr: {err}') - try: ctx.stream.write(data_block) except OSError as err: diff --git a/yt_dlp/extractor/youtube/_video.py b/yt_dlp/extractor/youtube/_video.py index 0527368e77..8c5486c4c2 100644 --- a/yt_dlp/extractor/youtube/_video.py +++ b/yt_dlp/extractor/youtube/_video.py @@ -2107,47 +2107,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor): return lambda s: ''.join(s[i] for i in cache_spec) - def _print_sig_code(self, func, example_sig): - if not self.get_param('youtube_print_sig_code'): - return - - def gen_sig_code(idxs): - def _genslice(start, end, step): - starts = '' if start == 0 else str(start) - ends = (':%d' % (end + step)) if end + step >= 0 else ':' - steps = '' if step == 1 else (':%d' % step) - return f's[{starts}{ends}{steps}]' - - step = None - # Quelch pyflakes warnings - start will be set when step is set - start = '(Never used)' - for i, prev in zip(idxs[1:], idxs[:-1]): - if step is not None: - if i - prev == step: - continue - yield _genslice(start, prev, step) - step = None - continue - if i - prev in [-1, 1]: - step = i - prev - start = prev - continue - else: - yield 's[%d]' % prev - if step is None: - yield 's[%d]' % i - else: - yield _genslice(start, i, step) - - test_string = ''.join(map(chr, range(len(example_sig)))) - cache_res = func(test_string) - cache_spec = [ord(c) for c in cache_res] - expr_code = ' + '.join(gen_sig_code(cache_spec)) - signature_id_tuple = '({})'.format(', '.join(str(len(p)) for p in example_sig.split('.'))) - code = (f'if tuple(len(p) for p in s.split(\'.\')) == {signature_id_tuple}:\n' - f' return {expr_code}\n') - self.to_screen('Extracted signature function:\n' + code) - def _parse_sig_js(self, jscode, player_url): # Examples where `sig` is funcname: # sig=function(a){a=a.split(""); ... ;return a.join("")}; @@ -2216,7 +2175,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor): extract_sig = self._cached( self._extract_signature_function, 'sig', player_url, self._signature_cache_id(s)) func = extract_sig(video_id, player_url, s) - self._print_sig_code(func, s) return func(s) def _decrypt_nsig(self, s, video_id, player_url): @@ -2226,11 +2184,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor): player_url = urljoin('https://www.youtube.com', player_url) try: - jsi, player_id, func_code = self._extract_n_function_code(video_id, player_url) + jsi, _, func_code = self._extract_n_function_code(video_id, player_url) except ExtractorError as e: raise ExtractorError('Unable to extract nsig function code', cause=e) - if self.get_param('youtube_print_sig_code'): - self.to_screen(f'Extracted nsig function from {player_id}:\n{func_code[1]}\n') try: extract_nsig = self._cached(self._extract_n_function_from_code, self._NSIG_FUNC_CACHE_ID, player_url) @@ -3580,23 +3536,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor): needs_live_processing = self._needs_live_processing(live_status, duration) skip_bad_formats = 'incomplete' not in format_types - if self._configuration_arg('include_incomplete_formats'): - skip_bad_formats = False - self._downloader.deprecated_feature('[youtube] include_incomplete_formats extractor argument is deprecated. ' - 'Use formats=incomplete extractor argument instead') skip_manifests = set(self._configuration_arg('skip')) - if (not self.get_param('youtube_include_hls_manifest', True) - or needs_live_processing == 'is_live' # These will be filtered out by YoutubeDL anyway + if (needs_live_processing == 'is_live' # These will be filtered out by YoutubeDL anyway or (needs_live_processing and skip_bad_formats)): skip_manifests.add('hls') - - if not self.get_param('youtube_include_dash_manifest', True): - skip_manifests.add('dash') - if self._configuration_arg('include_live_dash'): - self._downloader.deprecated_feature('[youtube] include_live_dash extractor argument is deprecated. ' - 'Use formats=incomplete extractor argument instead') - elif skip_bad_formats and live_status == 'is_live' and needs_live_processing != 'is_live': + if skip_bad_formats and live_status == 'is_live' and needs_live_processing != 'is_live': skip_manifests.add('dash') def process_manifest_format(f, proto, client_name, itag, missing_pot): diff --git a/yt_dlp/options.py b/yt_dlp/options.py index 29b37b4255..eaa4a7305f 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -389,10 +389,6 @@ def create_parser(): '--abort-on-error', '--no-ignore-errors', action='store_false', dest='ignoreerrors', help='Abort downloading of further videos if an error occurs (Alias: --no-ignore-errors)') - general.add_option( - '--dump-user-agent', - action='store_true', dest='dump_user_agent', default=False, - help='Display the current user-agent and exit') general.add_option( '--list-extractors', action='store_true', dest='list_extractors', default=False, @@ -616,10 +612,6 @@ def create_parser(): help=( 'Use this proxy to verify the IP address for some geo-restricted sites. ' 'The default proxy specified by --proxy (or none, if the option is not present) is used for the actual downloading')) - geo.add_option( - '--cn-verification-proxy', - dest='cn_verification_proxy', default=None, metavar='URL', - help=optparse.SUPPRESS_HELP) geo.add_option( '--xff', metavar='VALUE', dest='geo_bypass', default='default', @@ -778,14 +770,6 @@ def create_parser(): '--skip-playlist-after-errors', metavar='N', dest='skip_playlist_after_errors', default=None, type=int, help='Number of allowed failures until the rest of the playlist is skipped') - selection.add_option( - '--include-ads', - dest='include_ads', action='store_true', - help=optparse.SUPPRESS_HELP) - selection.add_option( - '--no-include-ads', - dest='include_ads', action='store_false', - help=optparse.SUPPRESS_HELP) authentication = optparse.OptionGroup(parser, 'Authentication Options') authentication.add_option( @@ -1071,10 +1055,6 @@ def create_parser(): '--no-lazy-playlist', action='store_false', dest='lazy_playlist', help='Process videos in the playlist only after the entire playlist is parsed (default)') - downloader.add_option( - '--xattr-set-filesize', - dest='xattr_set_filesize', action='store_true', - help='Set file xattribute ytdl.filesize with expected file size') downloader.add_option( '--hls-prefer-native', dest='hls_prefer_native', action='store_true', default=None, @@ -1335,7 +1315,7 @@ def create_parser(): action='store_true', dest='verbose', default=False, help='Print various debugging information') verbosity.add_option( - '--dump-pages', '--dump-intermediate-pages', + '--dump-pages', action='store_true', dest='dump_intermediate_pages', default=False, help='Print downloaded pages encoded using base64 to debug problems (very verbose)') verbosity.add_option( @@ -1347,23 +1327,9 @@ def create_parser(): action='store_true', dest='load_pages', default=False, help=optparse.SUPPRESS_HELP) verbosity.add_option( - '--youtube-print-sig-code', - action='store_true', dest='youtube_print_sig_code', default=False, - help=optparse.SUPPRESS_HELP) - verbosity.add_option( - '--print-traffic', '--dump-headers', + '--print-traffic', dest='debug_printtraffic', action='store_true', default=False, help='Display sent and read HTTP traffic') - verbosity.add_option( - '-C', '--call-home', - dest='call_home', action='store_true', default=False, - # help='Contact the yt-dlp server for debugging') - help=optparse.SUPPRESS_HELP) - verbosity.add_option( - '--no-call-home', - dest='call_home', action='store_false', - # help='Do not contact the yt-dlp server for debugging (default)') - help=optparse.SUPPRESS_HELP) filesystem = optparse.OptionGroup(parser, 'Filesystem Options') filesystem.add_option( @@ -1488,14 +1454,6 @@ def create_parser(): '--no-write-info-json', action='store_false', dest='writeinfojson', help='Do not write video metadata (default)') - filesystem.add_option( - '--write-annotations', - action='store_true', dest='writeannotations', default=False, - help=optparse.SUPPRESS_HELP) - filesystem.add_option( - '--no-write-annotations', - action='store_false', dest='writeannotations', - help=optparse.SUPPRESS_HELP) filesystem.add_option( '--write-playlist-metafiles', action='store_true', dest='allow_playlist_files', default=None, @@ -1755,15 +1713,7 @@ def create_parser(): 'detect_or_warn (the default; fix the file if we can, warn otherwise), ' 'force (try fixing even if the file already exists)')) postproc.add_option( - '--prefer-avconv', '--no-prefer-ffmpeg', - action='store_false', dest='prefer_ffmpeg', - help=optparse.SUPPRESS_HELP) - postproc.add_option( - '--prefer-ffmpeg', '--no-prefer-avconv', - action='store_true', dest='prefer_ffmpeg', default=True, - help=optparse.SUPPRESS_HELP) - postproc.add_option( - '--ffmpeg-location', '--avconv-location', metavar='PATH', + '--ffmpeg-location', metavar='PATH', dest='ffmpeg_location', help='Location of the ffmpeg binary; either the path to the binary or its containing directory') postproc.add_option( @@ -1900,38 +1850,6 @@ def create_parser(): default='https://sponsor.ajay.app', dest='sponsorblock_api', help='SponsorBlock API location, defaults to %default') - sponsorblock.add_option( - '--sponskrub', - action='store_true', dest='sponskrub', default=False, - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--no-sponskrub', - action='store_false', dest='sponskrub', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--sponskrub-cut', default=False, - action='store_true', dest='sponskrub_cut', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--no-sponskrub-cut', - action='store_false', dest='sponskrub_cut', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--sponskrub-force', default=False, - action='store_true', dest='sponskrub_force', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--no-sponskrub-force', - action='store_true', dest='sponskrub_force', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--sponskrub-location', metavar='PATH', - dest='sponskrub_path', default='', - help=optparse.SUPPRESS_HELP) - sponsorblock.add_option( - '--sponskrub-args', dest='sponskrub_args', metavar='ARGS', - help=optparse.SUPPRESS_HELP) - extractor = optparse.OptionGroup(parser, 'Extractor Options') extractor.add_option( '--extractor-retries', @@ -1967,22 +1885,56 @@ def create_parser(): }, help=( 'Pass ARGS arguments to the IE_KEY extractor. See "EXTRACTOR ARGUMENTS" for details. ' 'You can use this option multiple times to give arguments for different extractors')) - extractor.add_option( - '--youtube-include-dash-manifest', '--no-youtube-skip-dash-manifest', - action='store_true', dest='youtube_include_dash_manifest', default=True, - help=optparse.SUPPRESS_HELP) - extractor.add_option( - '--youtube-skip-dash-manifest', '--no-youtube-include-dash-manifest', - action='store_false', dest='youtube_include_dash_manifest', - help=optparse.SUPPRESS_HELP) - extractor.add_option( - '--youtube-include-hls-manifest', '--no-youtube-skip-hls-manifest', - action='store_true', dest='youtube_include_hls_manifest', default=True, - help=optparse.SUPPRESS_HELP) - extractor.add_option( - '--youtube-skip-hls-manifest', '--no-youtube-include-hls-manifest', - action='store_false', dest='youtube_include_hls_manifest', - help=optparse.SUPPRESS_HELP) + + def _deprecated_option_callback(option, opt_str, value, parser): + current = getattr(parser.values, '_deprecated_options', []) + parser.values._deprecated_options = [*current, opt_str] + + deprecated_switches = [ + '--xattr-set-filesize', + '--dump-user-agent', + '--youtube-include-dash-manifest', + '--no-youtube-skip-dash-manifest', + '--youtube-skip-dash-manifest', + '--no-youtube-include-dash-manifest', + '--youtube-include-hls-manifest', + '--no-youtube-skip-hls-manifest', + '--youtube-skip-hls-manifest', + '--no-youtube-include-hls-manifest', + '--youtube-print-sig-code', + '--sponskrub', + '--no-sponskrub', + '--sponskrub-cut', + '--no-sponskrub-cut', + '--sponskrub-force', + '--no-sponskrub-force', + '--prefer-avconv', + '--no-prefer-ffmpeg', + '--prefer-ffmpeg', + '--no-prefer-avconv', + '-C', # this needs to remain deprecated until at least 2028 + '--call-home', + '--no-call-home', + '--include-ads', + '--no-include-ads', + '--write-annotations', + '--no-write-annotations', + ] + deprecated_arguments = [ + '--sponskrub-location', + '--sponskrub-args', + '--cn-verification-proxy', + ] + + for opt in deprecated_switches: + parser.add_option( + opt, action='callback', callback=_deprecated_option_callback, + help=optparse.SUPPRESS_HELP) + for opt in deprecated_arguments: + parser.add_option( + opt, action='callback', callback=_deprecated_option_callback, + metavar='ARG', dest='_', type='str', + help=optparse.SUPPRESS_HELP) parser.add_option_group(general) parser.add_option_group(network) diff --git a/yt_dlp/postprocessor/__init__.py b/yt_dlp/postprocessor/__init__.py index 20e8b14b21..4bcc726494 100644 --- a/yt_dlp/postprocessor/__init__.py +++ b/yt_dlp/postprocessor/__init__.py @@ -30,7 +30,6 @@ from .metadataparser import ( ) from .modify_chapters import ModifyChaptersPP from .movefilesafterdownload import MoveFilesAfterDownloadPP -from .sponskrub import SponSkrubPP from .sponsorblock import SponsorBlockPP from .xattrpp import XAttrMetadataPP from ..globals import plugin_pps, postprocessors diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 59a49aa578..774625660a 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -88,7 +88,6 @@ class FFmpegPostProcessor(PostProcessor): def __init__(self, downloader=None): PostProcessor.__init__(self, downloader) - self._prefer_ffmpeg = self.get_param('prefer_ffmpeg', True) self._paths = self._determine_executables() @staticmethod @@ -100,10 +99,8 @@ class FFmpegPostProcessor(PostProcessor): def get_versions(downloader=None): return FFmpegPostProcessor.get_versions_and_features(downloader)[0] - _ffmpeg_to_avconv = {'ffmpeg': 'avconv', 'ffprobe': 'avprobe'} - def _determine_executables(self): - programs = [*self._ffmpeg_to_avconv.keys(), *self._ffmpeg_to_avconv.values()] + programs = ['ffmpeg', 'ffprobe'] location = self.get_param('ffmpeg_location', self._ffmpeg_location.get()) if location is None: @@ -119,8 +116,6 @@ class FFmpegPostProcessor(PostProcessor): filename = os.path.basename(location) basename = next((p for p in programs if p in filename), 'ffmpeg') dirname = os.path.dirname(os.path.abspath(location)) - if basename in self._ffmpeg_to_avconv: - self._prefer_ffmpeg = True paths = {p: os.path.join(dirname, p) for p in programs} if basename and basename in filename: @@ -179,17 +174,12 @@ class FFmpegPostProcessor(PostProcessor): def _get_version(self, kind): executables = (kind, ) - if not self._prefer_ffmpeg: - executables = (kind, self._ffmpeg_to_avconv[kind]) basename, version, features = next(filter( lambda x: x[1], ((p, *self._get_ffmpeg_version(p)) for p in executables)), (None, None, {})) if kind == 'ffmpeg': self.basename, self._features = basename, features else: self.probe_basename = basename - if basename == self._ffmpeg_to_avconv[kind]: - self.deprecated_feature(f'Support for {self._ffmpeg_to_avconv[kind]} is deprecated and ' - f'may be removed in a future version. Use {kind} instead') return version @functools.cached_property @@ -231,7 +221,7 @@ class FFmpegPostProcessor(PostProcessor): if not self.available: raise FFmpegPostProcessorError('ffmpeg not found. Please install or provide the path using --ffmpeg-location') - required_version = '10-0' if self.basename == 'avconv' else '1.0' + required_version = '1.0' if is_outdated_version(self._version, required_version): self.report_warning(f'Your copy of {self.basename} is outdated, update {self.basename} ' f'to version {required_version} or newer if you encounter any errors') @@ -842,17 +832,6 @@ class FFmpegMergerPP(FFmpegPostProcessor): def can_merge(self): # TODO: figure out merge-capable ffmpeg version - if self.basename != 'avconv': - return True - - required_version = '10-0' - if is_outdated_version( - self._versions[self.basename], required_version): - warning = (f'Your copy of {self.basename} is outdated and unable to properly mux separate video and audio files, ' - 'yt-dlp will download single file media. ' - f'Update {self.basename} to version {required_version} or newer to fix this.') - self.report_warning(warning) - return False return True diff --git a/yt_dlp/postprocessor/sponskrub.py b/yt_dlp/postprocessor/sponskrub.py deleted file mode 100644 index ac6db1bc7b..0000000000 --- a/yt_dlp/postprocessor/sponskrub.py +++ /dev/null @@ -1,97 +0,0 @@ -import os -import shlex -import subprocess - -from .common import PostProcessor -from ..utils import ( - Popen, - PostProcessingError, - check_executable, - cli_option, - encodeArgument, - prepend_extension, - shell_quote, - str_or_none, -) - - -# Deprecated in favor of the native implementation -class SponSkrubPP(PostProcessor): - _temp_ext = 'spons' - _exe_name = 'sponskrub' - - def __init__(self, downloader, path='', args=None, ignoreerror=False, cut=False, force=False, _from_cli=False): - PostProcessor.__init__(self, downloader) - self.force = force - self.cutout = cut - self.args = str_or_none(args) or '' # For backward compatibility - self.path = self.get_exe(path) - - if not _from_cli: - self.deprecation_warning( - 'yt_dlp.postprocessor.SponSkrubPP support is deprecated and may be removed in a future version. ' - 'Use yt_dlp.postprocessor.SponsorBlock and yt_dlp.postprocessor.ModifyChaptersPP instead') - - if not ignoreerror and self.path is None: - if path: - raise PostProcessingError(f'sponskrub not found in "{path}"') - else: - raise PostProcessingError('sponskrub not found. Please install or provide the path using --sponskrub-path') - - def get_exe(self, path=''): - if not path or not check_executable(path, ['-h']): - path = os.path.join(path, self._exe_name) - if not check_executable(path, ['-h']): - return None - return path - - @PostProcessor._restrict_to(images=False) - def run(self, information): - if self.path is None: - return [], information - - filename = information['filepath'] - if not os.path.exists(filename): # no download - return [], information - - if information['extractor_key'].lower() != 'youtube': - self.to_screen('Skipping sponskrub since it is not a YouTube video') - return [], information - if self.cutout and not self.force and not information.get('__real_download', False): - self.report_warning( - 'Skipping sponskrub since the video was already downloaded. ' - 'Use --sponskrub-force to run sponskrub anyway') - return [], information - - self.to_screen('Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark')) - if self.cutout: - self.report_warning('Cutting out sponsor segments will cause the subtitles to go out of sync.') - if not information.get('__real_download', False): - self.report_warning('If sponskrub is run multiple times, unintended parts of the video could be cut out.') - - temp_filename = prepend_extension(filename, self._temp_ext) - if os.path.exists(temp_filename): - os.remove(temp_filename) - - cmd = [self.path] - if not self.cutout: - cmd += ['-chapter'] - cmd += cli_option(self._downloader.params, '-proxy', 'proxy') - cmd += shlex.split(self.args) # For backward compatibility - cmd += self._configuration_args(self._exe_name, use_compat=False) - cmd += ['--', information['id'], filename, temp_filename] - cmd = [encodeArgument(i) for i in cmd] - - self.write_debug(f'sponskrub command line: {shell_quote(cmd)}') - stdout, _, returncode = Popen.run(cmd, text=True, stdout=None if self.get_param('verbose') else subprocess.PIPE) - - if not returncode: - os.replace(temp_filename, filename) - self.to_screen('Sponsor sections have been %s' % ('removed' if self.cutout else 'marked')) - elif returncode == 3: - self.to_screen('No segments in the SponsorBlock database') - else: - raise PostProcessingError( - stdout.strip().splitlines()[0 if stdout.strip().lower().startswith('unrecognised') else -1] - or f'sponskrub failed with error code {returncode}') - return [], information