[cleanup] Deprecate various options (#13821)

Closes #14198, Closes #12909
Authored by: seproDev
This commit is contained in:
sepro
2025-09-21 17:10:37 +02:00
committed by GitHub
parent 98b6b0d339
commit 08d7899683
14 changed files with 83 additions and 487 deletions

View File

@@ -241,8 +241,6 @@ The following provide support for impersonating browser requests. This may be re
### Deprecated ### 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) * [**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) * [**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" --hls-prefer-ffmpeg --downloader "m3u8:ffmpeg"
--list-formats-old --compat-options list-formats (Alias: --no-list-formats-as-table) --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) --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" --geo-bypass --xff "default"
--no-geo-bypass --xff "never" --no-geo-bypass --xff "never"
--geo-bypass-country CODE --xff CODE --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 --test Download only part of video for testing extractors
--load-pages Load pages dumped by --write-pages --load-pages Load pages dumped by --write-pages
--youtube-print-sig-code For testing youtube signatures
--allow-unplayable-formats List unplayable formats also --allow-unplayable-formats List unplayable formats also
--no-allow-unplayable-formats Default --no-allow-unplayable-formats Default
#### Old aliases #### Old aliases
These are aliases that are no longer documented for various reasons These are aliases that are no longer documented for various reasons
--avconv-location --ffmpeg-location
--clean-infojson --clean-info-json --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 --force-write-download-archive --force-write-archive
--no-clean-infojson --no-clean-info-json --no-clean-infojson --no-clean-info-json
--no-split-tracks --no-split-chapters --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 --yes-overwrites --force-overwrites
#### Sponskrub Options #### 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 --sponskrub --sponsorblock-mark all
--no-sponskrub --no-sponsorblock --no-sponskrub --no-sponsorblock
@@ -2424,6 +2413,17 @@ These options may no longer work as intended
--no-include-ads Default --no-include-ads Default
--write-annotations No supported site has annotations now --write-annotations No supported site has annotations now
--no-write-annotations Default --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 seperate-video-versions No longer needed
--compat-options no-youtube-prefer-utc-upload-date No longer supported --compat-options no-youtube-prefer-utc-upload-date No longer supported

View File

@@ -36,7 +36,6 @@
"verbose": true, "verbose": true,
"writedescription": false, "writedescription": false,
"writeinfojson": true, "writeinfojson": true,
"writeannotations": false,
"writelink": false, "writelink": false,
"writeurllink": false, "writeurllink": false,
"writewebloclink": false, "writewebloclink": false,

View File

@@ -20,7 +20,7 @@ import random
import ssl import ssl
import threading import threading
from yt_dlp import socks, traverse_obj from yt_dlp import socks
from yt_dlp.cookies import YoutubeDLCookieJar from yt_dlp.cookies import YoutubeDLCookieJar
from yt_dlp.dependencies import websockets from yt_dlp.dependencies import websockets
from yt_dlp.networking import Request from yt_dlp.networking import Request
@@ -32,6 +32,7 @@ from yt_dlp.networking.exceptions import (
SSLError, SSLError,
TransportError, TransportError,
) )
from yt_dlp.utils.traversal import traverse_obj
from yt_dlp.utils.networking import HTTPHeaderDict from yt_dlp.utils.networking import HTTPHeaderDict
TEST_DIR = os.path.dirname(os.path.abspath(__file__)) TEST_DIR = os.path.dirname(os.path.abspath(__file__))

View File

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

View File

@@ -304,7 +304,6 @@ class YoutubeDL:
clean_infojson: Remove internal metadata from the infojson clean_infojson: Remove internal metadata from the infojson
getcomments: Extract video comments. This will not be written to disk getcomments: Extract video comments. This will not be written to disk
unless writeinfojson is also given unless writeinfojson is also given
writeannotations: Write the video annotations to a .annotations.xml file
writethumbnail: Write the thumbnail image to a file writethumbnail: Write the thumbnail image to a file
allow_playlist_files: Whether to write playlists' description, infojson etc allow_playlist_files: Whether to write playlists' description, infojson etc
also to disk when using the 'write*' options also to disk when using the 'write*' options
@@ -511,11 +510,11 @@ class YoutubeDL:
the downloader (see yt_dlp/downloader/common.py): the downloader (see yt_dlp/downloader/common.py):
nopart, updatetime, buffersize, ratelimit, throttledratelimit, min_filesize, nopart, updatetime, buffersize, ratelimit, throttledratelimit, min_filesize,
max_filesize, test, noresizebuffer, retries, file_access_retries, fragment_retries, max_filesize, test, noresizebuffer, retries, file_access_retries, fragment_retries,
continuedl, xattr_set_filesize, hls_use_mpegts, http_chunk_size, continuedl, hls_use_mpegts, http_chunk_size, external_downloader_args,
external_downloader_args, concurrent_fragment_downloads, progress_delta. concurrent_fragment_downloads, progress_delta.
The following options are used by the post processors: 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. to the binary or its containing directory.
postprocessor_args: A dictionary of postprocessor/executable keys (in lower case) postprocessor_args: A dictionary of postprocessor/executable keys (in lower case)
and a list of additional command-line arguments for the and a list of additional command-line arguments for the
@@ -566,32 +565,14 @@ class YoutubeDL:
allsubtitles: - Use subtitleslangs = ['all'] allsubtitles: - Use subtitleslangs = ['all']
Downloads all the subtitles of the video Downloads all the subtitles of the video
(requires writesubtitles or writeautomaticsub) (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 post_hooks: - Register a custom postprocessor
A list of functions that get called as the final step A list of functions that get called as the final step
for each video file, after all postprocessors have been for each video file, after all postprocessors have been
called. The filename will be passed as the only argument. called. The filename will be passed as the only argument.
hls_prefer_native: - Use external_downloader = {'m3u8': 'native'} or {'m3u8': 'ffmpeg'}. hls_prefer_native: - Use external_downloader = {'m3u8': 'native'} or {'m3u8': 'ffmpeg'}.
Use the native HLS downloader instead of ffmpeg/avconv Use the native HLS downloader instead of ffmpeg
if True, otherwise use ffmpeg/avconv if False, otherwise if True, otherwise use ffmpeg if False, otherwise
use downloader suggested by extractor if None. 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_color: Same as `color='no_color'`
no_overwrites: Same as `overwrites=False` no_overwrites: Same as `overwrites=False`
""" """
@@ -750,10 +731,6 @@ class YoutubeDL:
return True return True
return False 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"') check_deprecated('useid', '--id', '-o "%(id)s.%(ext)s"')
for msg in self.params.get('_warnings', []): for msg in self.params.get('_warnings', []):
@@ -3335,28 +3312,6 @@ class YoutubeDL:
elif _infojson_written is None: elif _infojson_written is None:
return 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 # Write internet shortcut files
def _write_link_file(link_type): def _write_link_file(link_type):
url = try_get(info_dict['webpage_url'], iri_to_uri) url = try_get(info_dict['webpage_url'], iri_to_uri)

View File

@@ -59,11 +59,9 @@ from .utils import (
render_table, render_table,
setproctitle, setproctitle,
shell_quote, shell_quote,
traverse_obj,
variadic, variadic,
write_string, write_string,
) )
from .utils.networking import std_headers
from .utils._utils import _UnsafeExtensionError from .utils._utils import _UnsafeExtensionError
from .YoutubeDL import YoutubeDL from .YoutubeDL import YoutubeDL
@@ -523,7 +521,6 @@ def validate_options(opts):
if report_args_compat('post-processor', opts.postprocessor_args, 'default-compat', 'default'): 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['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', def report_conflict(arg1, opt1, arg2='--allow-unplayable-formats', opt2='allow_unplayable_formats',
val1=NO_DEFAULT, val2=NO_DEFAULT, default=False): 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')) '"--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('--id', 'useid', '--output', 'outtmpl', val2=opts.outtmpl.get('default'))
report_conflict('--remux-video', 'remuxvideo', '--recode-video', 'recodevideo') 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 # Conflicts with --allow-unplayable-formats
report_conflict('--embed-metadata', 'addmetadata') report_conflict('--embed-metadata', 'addmetadata')
@@ -565,23 +557,15 @@ def validate_options(opts):
report_conflict('--recode-video', 'recodevideo') report_conflict('--recode-video', 'recodevideo')
report_conflict('--remove-chapters', 'remove_chapters', default=[]) report_conflict('--remove-chapters', 'remove_chapters', default=[])
report_conflict('--remux-video', 'remuxvideo') report_conflict('--remux-video', 'remuxvideo')
report_conflict('--sponskrub', 'sponskrub')
report_conflict('--sponsorblock-remove', 'sponsorblock_remove', default=set()) report_conflict('--sponsorblock-remove', 'sponsorblock_remove', default=set())
report_conflict('--xattrs', 'xattrs') report_conflict('--xattrs', 'xattrs')
# Fully deprecated options if hasattr(opts, '_deprecated_options'):
def report_deprecation(val, old, new=None):
if not val:
return
deprecation_warnings.append( deprecation_warnings.append(
f'{old} is deprecated and may be removed in a future version. Use {new} instead' if new f'The following options have been deprecated: {", ".join(opts._deprecated_options)}\n'
else f'{old} is deprecated and may not work as expected') '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')
report_deprecation(opts.sponskrub, '--sponskrub', '--sponsorblock-mark or --sponsorblock-remove') del opts._deprecated_options
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
# Dependent options # Dependent options
opts.date = DateRange.day(opts.date) if opts.date else DateRange(opts.dateafter, opts.datebefore) 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_metadata': opts.addmetadata,
'add_infojson': opts.embed_infojson, '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: if opts.embedthumbnail:
yield { yield {
'key': 'EmbedThumbnail', 'key': 'EmbedThumbnail',
@@ -885,7 +854,6 @@ def parse_options(argv=None):
'nopart': opts.nopart, 'nopart': opts.nopart,
'updatetime': opts.updatetime, 'updatetime': opts.updatetime,
'writedescription': opts.writedescription, 'writedescription': opts.writedescription,
'writeannotations': opts.writeannotations,
'writeinfojson': opts.writeinfojson, 'writeinfojson': opts.writeinfojson,
'allow_playlist_files': opts.allow_playlist_files, 'allow_playlist_files': opts.allow_playlist_files,
'clean_infojson': opts.clean_infojson, 'clean_infojson': opts.clean_infojson,
@@ -919,7 +887,6 @@ def parse_options(argv=None):
'max_views': opts.max_views, 'max_views': opts.max_views,
'daterange': opts.date, 'daterange': opts.date,
'cachedir': opts.cachedir, 'cachedir': opts.cachedir,
'youtube_print_sig_code': opts.youtube_print_sig_code,
'age_limit': opts.age_limit, 'age_limit': opts.age_limit,
'download_archive': opts.download_archive, 'download_archive': opts.download_archive,
'break_on_existing': opts.break_on_existing, 'break_on_existing': opts.break_on_existing,
@@ -937,13 +904,9 @@ def parse_options(argv=None):
'socket_timeout': opts.socket_timeout, 'socket_timeout': opts.socket_timeout,
'bidi_workaround': opts.bidi_workaround, 'bidi_workaround': opts.bidi_workaround,
'debug_printtraffic': opts.debug_printtraffic, 'debug_printtraffic': opts.debug_printtraffic,
'prefer_ffmpeg': opts.prefer_ffmpeg,
'include_ads': opts.include_ads,
'default_search': opts.default_search, 'default_search': opts.default_search,
'dynamic_mpd': opts.dynamic_mpd, 'dynamic_mpd': opts.dynamic_mpd,
'extractor_args': opts.extractor_args, '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, 'encoding': opts.encoding,
'extract_flat': opts.extract_flat, 'extract_flat': opts.extract_flat,
'live_from_start': opts.live_from_start, 'live_from_start': opts.live_from_start,
@@ -955,7 +918,6 @@ def parse_options(argv=None):
'fixup': opts.fixup, 'fixup': opts.fixup,
'source_address': opts.source_address, 'source_address': opts.source_address,
'impersonate': opts.impersonate, 'impersonate': opts.impersonate,
'call_home': opts.call_home,
'sleep_interval_requests': opts.sleep_interval_requests, 'sleep_interval_requests': opts.sleep_interval_requests,
'sleep_interval': opts.sleep_interval, 'sleep_interval': opts.sleep_interval,
'max_sleep_interval': opts.max_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, 'force_keyframes_at_cuts': opts.force_keyframes_at_cuts,
'list_thumbnails': opts.list_thumbnails, 'list_thumbnails': opts.list_thumbnails,
'playlist_items': opts.playlist_items, 'playlist_items': opts.playlist_items,
'xattr_set_filesize': opts.xattr_set_filesize,
'match_filter': opts.match_filter, 'match_filter': opts.match_filter,
'color': opts.color, 'color': opts.color,
'ffmpeg_location': opts.ffmpeg_location, 'ffmpeg_location': opts.ffmpeg_location,
@@ -974,7 +935,6 @@ def parse_options(argv=None):
'hls_split_discontinuity': opts.hls_split_discontinuity, 'hls_split_discontinuity': opts.hls_split_discontinuity,
'external_downloader_args': opts.external_downloader_args, 'external_downloader_args': opts.external_downloader_args,
'postprocessor_args': opts.postprocessor_args, 'postprocessor_args': opts.postprocessor_args,
'cn_verification_proxy': opts.cn_verification_proxy,
'geo_verification_proxy': opts.geo_verification_proxy, 'geo_verification_proxy': opts.geo_verification_proxy,
'geo_bypass': opts.geo_bypass, 'geo_bypass': opts.geo_bypass,
'geo_bypass_country': opts.geo_bypass_country, '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) 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): if print_extractor_information(opts, all_urls):
return return

View File

@@ -62,7 +62,6 @@ class FileDownloader:
test: Download only first bytes to test the downloader. test: Download only first bytes to test the downloader.
min_filesize: Skip files smaller than this size min_filesize: Skip files smaller than this size
max_filesize: Skip files larger 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 progress_delta: The minimum time between progress output, in seconds
external_downloader_args: A dictionary of downloader keys (in lower case) external_downloader_args: A dictionary of downloader keys (in lower case)
and a list of additional command-line arguments for the and a list of additional command-line arguments for the

View File

@@ -563,7 +563,7 @@ class FFmpegFD(ExternalFD):
f'{cookie.name}={cookie.value}; path={cookie.path}; domain={cookie.domain};\r\n' f'{cookie.name}={cookie.value}; path={cookie.path}; domain={cookie.domain};\r\n'
for cookie in cookies)]) for cookie in cookies)])
if fmt.get('http_headers') and is_http: 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. # [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())]) 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 return retval
class AVconvFD(FFmpegFD):
pass
_BY_NAME = { _BY_NAME = {
klass.get_basename(): klass klass.get_basename(): klass
for name, klass in globals().items() for name, klass in globals().items()

View File

@@ -13,12 +13,9 @@ from ..utils import (
ContentTooShortError, ContentTooShortError,
RetryManager, RetryManager,
ThrottledDownload, ThrottledDownload,
XAttrMetadataError,
XAttrUnavailableError,
int_or_none, int_or_none,
parse_http_range, parse_http_range,
try_call, try_call,
write_xattr,
) )
from ..utils.networking import HTTPHeaderDict from ..utils.networking import HTTPHeaderDict
@@ -273,12 +270,6 @@ class HttpFD(FileDownloader):
self.report_error(f'unable to open for writing: {err}') self.report_error(f'unable to open for writing: {err}')
return False 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: try:
ctx.stream.write(data_block) ctx.stream.write(data_block)
except OSError as err: except OSError as err:

View File

@@ -2107,47 +2107,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
return lambda s: ''.join(s[i] for i in cache_spec) 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): def _parse_sig_js(self, jscode, player_url):
# Examples where `sig` is funcname: # Examples where `sig` is funcname:
# sig=function(a){a=a.split(""); ... ;return a.join("")}; # sig=function(a){a=a.split(""); ... ;return a.join("")};
@@ -2216,7 +2175,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
extract_sig = self._cached( extract_sig = self._cached(
self._extract_signature_function, 'sig', player_url, self._signature_cache_id(s)) self._extract_signature_function, 'sig', player_url, self._signature_cache_id(s))
func = extract_sig(video_id, player_url, s) func = extract_sig(video_id, player_url, s)
self._print_sig_code(func, s)
return func(s) return func(s)
def _decrypt_nsig(self, s, video_id, player_url): 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) player_url = urljoin('https://www.youtube.com', player_url)
try: 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: except ExtractorError as e:
raise ExtractorError('Unable to extract nsig function code', cause=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: try:
extract_nsig = self._cached(self._extract_n_function_from_code, self._NSIG_FUNC_CACHE_ID, player_url) 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) needs_live_processing = self._needs_live_processing(live_status, duration)
skip_bad_formats = 'incomplete' not in format_types 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')) skip_manifests = set(self._configuration_arg('skip'))
if (not self.get_param('youtube_include_hls_manifest', True) if (needs_live_processing == 'is_live' # These will be filtered out by YoutubeDL anyway
or needs_live_processing == 'is_live' # These will be filtered out by YoutubeDL anyway
or (needs_live_processing and skip_bad_formats)): or (needs_live_processing and skip_bad_formats)):
skip_manifests.add('hls') skip_manifests.add('hls')
if skip_bad_formats and live_status == 'is_live' and needs_live_processing != 'is_live':
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':
skip_manifests.add('dash') skip_manifests.add('dash')
def process_manifest_format(f, proto, client_name, itag, missing_pot): def process_manifest_format(f, proto, client_name, itag, missing_pot):

View File

@@ -389,10 +389,6 @@ def create_parser():
'--abort-on-error', '--no-ignore-errors', '--abort-on-error', '--no-ignore-errors',
action='store_false', dest='ignoreerrors', action='store_false', dest='ignoreerrors',
help='Abort downloading of further videos if an error occurs (Alias: --no-ignore-errors)') 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( general.add_option(
'--list-extractors', '--list-extractors',
action='store_true', dest='list_extractors', default=False, action='store_true', dest='list_extractors', default=False,
@@ -616,10 +612,6 @@ def create_parser():
help=( help=(
'Use this proxy to verify the IP address for some geo-restricted sites. ' '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')) '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( geo.add_option(
'--xff', metavar='VALUE', '--xff', metavar='VALUE',
dest='geo_bypass', default='default', dest='geo_bypass', default='default',
@@ -778,14 +770,6 @@ def create_parser():
'--skip-playlist-after-errors', metavar='N', '--skip-playlist-after-errors', metavar='N',
dest='skip_playlist_after_errors', default=None, type=int, dest='skip_playlist_after_errors', default=None, type=int,
help='Number of allowed failures until the rest of the playlist is skipped') 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 = optparse.OptionGroup(parser, 'Authentication Options')
authentication.add_option( authentication.add_option(
@@ -1071,10 +1055,6 @@ def create_parser():
'--no-lazy-playlist', '--no-lazy-playlist',
action='store_false', dest='lazy_playlist', action='store_false', dest='lazy_playlist',
help='Process videos in the playlist only after the entire playlist is parsed (default)') 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( downloader.add_option(
'--hls-prefer-native', '--hls-prefer-native',
dest='hls_prefer_native', action='store_true', default=None, dest='hls_prefer_native', action='store_true', default=None,
@@ -1335,7 +1315,7 @@ def create_parser():
action='store_true', dest='verbose', default=False, action='store_true', dest='verbose', default=False,
help='Print various debugging information') help='Print various debugging information')
verbosity.add_option( verbosity.add_option(
'--dump-pages', '--dump-intermediate-pages', '--dump-pages',
action='store_true', dest='dump_intermediate_pages', default=False, action='store_true', dest='dump_intermediate_pages', default=False,
help='Print downloaded pages encoded using base64 to debug problems (very verbose)') help='Print downloaded pages encoded using base64 to debug problems (very verbose)')
verbosity.add_option( verbosity.add_option(
@@ -1347,23 +1327,9 @@ def create_parser():
action='store_true', dest='load_pages', default=False, action='store_true', dest='load_pages', default=False,
help=optparse.SUPPRESS_HELP) help=optparse.SUPPRESS_HELP)
verbosity.add_option( verbosity.add_option(
'--youtube-print-sig-code', '--print-traffic',
action='store_true', dest='youtube_print_sig_code', default=False,
help=optparse.SUPPRESS_HELP)
verbosity.add_option(
'--print-traffic', '--dump-headers',
dest='debug_printtraffic', action='store_true', default=False, dest='debug_printtraffic', action='store_true', default=False,
help='Display sent and read HTTP traffic') 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 = optparse.OptionGroup(parser, 'Filesystem Options')
filesystem.add_option( filesystem.add_option(
@@ -1488,14 +1454,6 @@ def create_parser():
'--no-write-info-json', '--no-write-info-json',
action='store_false', dest='writeinfojson', action='store_false', dest='writeinfojson',
help='Do not write video metadata (default)') 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( filesystem.add_option(
'--write-playlist-metafiles', '--write-playlist-metafiles',
action='store_true', dest='allow_playlist_files', default=None, 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), ' 'detect_or_warn (the default; fix the file if we can, warn otherwise), '
'force (try fixing even if the file already exists)')) 'force (try fixing even if the file already exists)'))
postproc.add_option( postproc.add_option(
'--prefer-avconv', '--no-prefer-ffmpeg', '--ffmpeg-location', metavar='PATH',
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',
dest='ffmpeg_location', dest='ffmpeg_location',
help='Location of the ffmpeg binary; either the path to the binary or its containing directory') help='Location of the ffmpeg binary; either the path to the binary or its containing directory')
postproc.add_option( postproc.add_option(
@@ -1900,38 +1850,6 @@ def create_parser():
default='https://sponsor.ajay.app', dest='sponsorblock_api', default='https://sponsor.ajay.app', dest='sponsorblock_api',
help='SponsorBlock API location, defaults to %default') 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 = optparse.OptionGroup(parser, 'Extractor Options')
extractor.add_option( extractor.add_option(
'--extractor-retries', '--extractor-retries',
@@ -1967,22 +1885,56 @@ def create_parser():
}, help=( }, help=(
'Pass ARGS arguments to the IE_KEY extractor. See "EXTRACTOR ARGUMENTS" for details. ' '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')) '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', def _deprecated_option_callback(option, opt_str, value, parser):
action='store_true', dest='youtube_include_dash_manifest', default=True, current = getattr(parser.values, '_deprecated_options', [])
help=optparse.SUPPRESS_HELP) parser.values._deprecated_options = [*current, opt_str]
extractor.add_option(
'--youtube-skip-dash-manifest', '--no-youtube-include-dash-manifest', deprecated_switches = [
action='store_false', dest='youtube_include_dash_manifest', '--xattr-set-filesize',
help=optparse.SUPPRESS_HELP) '--dump-user-agent',
extractor.add_option( '--youtube-include-dash-manifest',
'--youtube-include-hls-manifest', '--no-youtube-skip-hls-manifest', '--no-youtube-skip-dash-manifest',
action='store_true', dest='youtube_include_hls_manifest', default=True, '--youtube-skip-dash-manifest',
help=optparse.SUPPRESS_HELP) '--no-youtube-include-dash-manifest',
extractor.add_option( '--youtube-include-hls-manifest',
'--youtube-skip-hls-manifest', '--no-youtube-include-hls-manifest', '--no-youtube-skip-hls-manifest',
action='store_false', dest='youtube_include_hls_manifest', '--youtube-skip-hls-manifest',
help=optparse.SUPPRESS_HELP) '--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(general)
parser.add_option_group(network) parser.add_option_group(network)

View File

@@ -30,7 +30,6 @@ from .metadataparser import (
) )
from .modify_chapters import ModifyChaptersPP from .modify_chapters import ModifyChaptersPP
from .movefilesafterdownload import MoveFilesAfterDownloadPP from .movefilesafterdownload import MoveFilesAfterDownloadPP
from .sponskrub import SponSkrubPP
from .sponsorblock import SponsorBlockPP from .sponsorblock import SponsorBlockPP
from .xattrpp import XAttrMetadataPP from .xattrpp import XAttrMetadataPP
from ..globals import plugin_pps, postprocessors from ..globals import plugin_pps, postprocessors

View File

@@ -88,7 +88,6 @@ class FFmpegPostProcessor(PostProcessor):
def __init__(self, downloader=None): def __init__(self, downloader=None):
PostProcessor.__init__(self, downloader) PostProcessor.__init__(self, downloader)
self._prefer_ffmpeg = self.get_param('prefer_ffmpeg', True)
self._paths = self._determine_executables() self._paths = self._determine_executables()
@staticmethod @staticmethod
@@ -100,10 +99,8 @@ class FFmpegPostProcessor(PostProcessor):
def get_versions(downloader=None): def get_versions(downloader=None):
return FFmpegPostProcessor.get_versions_and_features(downloader)[0] return FFmpegPostProcessor.get_versions_and_features(downloader)[0]
_ffmpeg_to_avconv = {'ffmpeg': 'avconv', 'ffprobe': 'avprobe'}
def _determine_executables(self): 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()) location = self.get_param('ffmpeg_location', self._ffmpeg_location.get())
if location is None: if location is None:
@@ -119,8 +116,6 @@ class FFmpegPostProcessor(PostProcessor):
filename = os.path.basename(location) filename = os.path.basename(location)
basename = next((p for p in programs if p in filename), 'ffmpeg') basename = next((p for p in programs if p in filename), 'ffmpeg')
dirname = os.path.dirname(os.path.abspath(location)) 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} paths = {p: os.path.join(dirname, p) for p in programs}
if basename and basename in filename: if basename and basename in filename:
@@ -179,17 +174,12 @@ class FFmpegPostProcessor(PostProcessor):
def _get_version(self, kind): def _get_version(self, kind):
executables = (kind, ) executables = (kind, )
if not self._prefer_ffmpeg:
executables = (kind, self._ffmpeg_to_avconv[kind])
basename, version, features = next(filter( basename, version, features = next(filter(
lambda x: x[1], ((p, *self._get_ffmpeg_version(p)) for p in executables)), (None, None, {})) lambda x: x[1], ((p, *self._get_ffmpeg_version(p)) for p in executables)), (None, None, {}))
if kind == 'ffmpeg': if kind == 'ffmpeg':
self.basename, self._features = basename, features self.basename, self._features = basename, features
else: else:
self.probe_basename = basename 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 return version
@functools.cached_property @functools.cached_property
@@ -231,7 +221,7 @@ class FFmpegPostProcessor(PostProcessor):
if not self.available: if not self.available:
raise FFmpegPostProcessorError('ffmpeg not found. Please install or provide the path using --ffmpeg-location') 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): if is_outdated_version(self._version, required_version):
self.report_warning(f'Your copy of {self.basename} is outdated, update {self.basename} ' 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') f'to version {required_version} or newer if you encounter any errors')
@@ -842,17 +832,6 @@ class FFmpegMergerPP(FFmpegPostProcessor):
def can_merge(self): def can_merge(self):
# TODO: figure out merge-capable ffmpeg version # 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 return True

View File

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