mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-14 21:23:05 +00:00
Compare commits
5 Commits
24e3d87431
...
592b748582
Author | SHA1 | Date | |
---|---|---|---|
|
592b748582 | ||
|
cf4f42cb97 | ||
|
da1d734fbe | ||
|
2b38f7b2bc | ||
|
76aa991374 |
@ -71,7 +71,7 @@ yt-dlp is a [youtube-dl](https://github.com/ytdl-org/youtube-dl) fork based on t
|
|||||||
|
|
||||||
# NEW FEATURES
|
# NEW FEATURES
|
||||||
|
|
||||||
* Based on **youtube-dl 2021.12.17 [commit/5add3f4](https://github.com/ytdl-org/youtube-dl/commit/5add3f4373287e6346ca3551239edab549284db3)** and **youtube-dlc 2020.11.11-3 [commit/f9401f2](https://github.com/blackjack4494/yt-dlc/commit/f9401f2a91987068139c5f757b12fc711d4c0cee)**: You get all the features and patches of [youtube-dlc](https://github.com/blackjack4494/yt-dlc) in addition to the latest [youtube-dl](https://github.com/ytdl-org/youtube-dl)
|
* Based on **youtube-dl 2021.12.17 [commit/6508688](https://github.com/ytdl-org/youtube-dl/commit/6508688e88c83bb811653083db9351702cd39a6a)** and **youtube-dlc 2020.11.11-3 [commit/f9401f2](https://github.com/blackjack4494/yt-dlc/commit/f9401f2a91987068139c5f757b12fc711d4c0cee)**: You get all the features and patches of [youtube-dlc](https://github.com/blackjack4494/yt-dlc) in addition to the latest [youtube-dl](https://github.com/ytdl-org/youtube-dl)
|
||||||
|
|
||||||
* **[SponsorBlock Integration](#sponsorblock-options)**: You can mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API
|
* **[SponsorBlock Integration](#sponsorblock-options)**: You can mark/remove sponsor sections in youtube videos by utilizing the [SponsorBlock](https://sponsor.ajay.app) API
|
||||||
|
|
||||||
|
@ -518,17 +518,6 @@ class YoutubeDL(object):
|
|||||||
'storyboards': {'mhtml'},
|
'storyboards': {'mhtml'},
|
||||||
}
|
}
|
||||||
|
|
||||||
params = None
|
|
||||||
_ies = {}
|
|
||||||
_pps = {k: [] for k in POSTPROCESS_WHEN}
|
|
||||||
_printed_messages = set()
|
|
||||||
_first_webpage_request = True
|
|
||||||
_download_retcode = None
|
|
||||||
_num_downloads = None
|
|
||||||
_playlist_level = 0
|
|
||||||
_playlist_urls = set()
|
|
||||||
_screen_file = None
|
|
||||||
|
|
||||||
def __init__(self, params=None, auto_init=True):
|
def __init__(self, params=None, auto_init=True):
|
||||||
"""Create a FileDownloader object with the given options.
|
"""Create a FileDownloader object with the given options.
|
||||||
@param auto_init Whether to load the default extractors and print header (if verbose).
|
@param auto_init Whether to load the default extractors and print header (if verbose).
|
||||||
@ -536,6 +525,7 @@ class YoutubeDL(object):
|
|||||||
"""
|
"""
|
||||||
if params is None:
|
if params is None:
|
||||||
params = {}
|
params = {}
|
||||||
|
self.params = params
|
||||||
self._ies = {}
|
self._ies = {}
|
||||||
self._ies_instances = {}
|
self._ies_instances = {}
|
||||||
self._pps = {k: [] for k in POSTPROCESS_WHEN}
|
self._pps = {k: [] for k in POSTPROCESS_WHEN}
|
||||||
@ -547,15 +537,21 @@ class YoutubeDL(object):
|
|||||||
self._download_retcode = 0
|
self._download_retcode = 0
|
||||||
self._num_downloads = 0
|
self._num_downloads = 0
|
||||||
self._num_videos = 0
|
self._num_videos = 0
|
||||||
self._screen_file = [sys.stdout, sys.stderr][params.get('logtostderr', False)]
|
self._playlist_level = 0
|
||||||
self._err_file = sys.stderr
|
self._playlist_urls = set()
|
||||||
self.params = params
|
|
||||||
self.cache = Cache(self)
|
self.cache = Cache(self)
|
||||||
|
|
||||||
windows_enable_vt_mode()
|
windows_enable_vt_mode()
|
||||||
|
self._out_files = {
|
||||||
|
'error': sys.stderr,
|
||||||
|
'print': sys.stderr if self.params.get('logtostderr') else sys.stdout,
|
||||||
|
'console': None if compat_os_name == 'nt' else next(
|
||||||
|
filter(supports_terminal_sequences, (sys.stderr, sys.stdout)), None)
|
||||||
|
}
|
||||||
|
self._out_files['screen'] = sys.stderr if self.params.get('quiet') else self._out_files['print']
|
||||||
self._allow_colors = {
|
self._allow_colors = {
|
||||||
'screen': not self.params.get('no_color') and supports_terminal_sequences(self._screen_file),
|
type_: not self.params.get('no_color') and supports_terminal_sequences(self._out_files[type_])
|
||||||
'err': not self.params.get('no_color') and supports_terminal_sequences(self._err_file),
|
for type_ in ('screen', 'error')
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.version_info < (3, 6):
|
if sys.version_info < (3, 6):
|
||||||
@ -620,7 +616,7 @@ class YoutubeDL(object):
|
|||||||
sp_kwargs = dict(
|
sp_kwargs = dict(
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=slave,
|
stdout=slave,
|
||||||
stderr=self._err_file)
|
stderr=self._out_files['error'])
|
||||||
try:
|
try:
|
||||||
self._output_process = Popen(['bidiv'] + width_args, **sp_kwargs)
|
self._output_process = Popen(['bidiv'] + width_args, **sp_kwargs)
|
||||||
except OSError:
|
except OSError:
|
||||||
@ -788,14 +784,24 @@ class YoutubeDL(object):
|
|||||||
self._printed_messages.add(message)
|
self._printed_messages.add(message)
|
||||||
write_string(message, out=out, encoding=self.params.get('encoding'))
|
write_string(message, out=out, encoding=self.params.get('encoding'))
|
||||||
|
|
||||||
def to_stdout(self, message, skip_eol=False, quiet=False):
|
def to_stdout(self, message, skip_eol=False, quiet=None):
|
||||||
"""Print message to stdout"""
|
"""Print message to stdout"""
|
||||||
|
if quiet is not None:
|
||||||
|
self.deprecation_warning('"ydl.to_stdout" no longer accepts the argument quiet. Use "ydl.to_screen" instead')
|
||||||
|
self._write_string(
|
||||||
|
'%s%s' % (self._bidi_workaround(message), ('' if skip_eol else '\n')),
|
||||||
|
self._out_files['print'])
|
||||||
|
|
||||||
|
def to_screen(self, message, skip_eol=False, quiet=None):
|
||||||
|
"""Print message to screen if not in quiet mode"""
|
||||||
if self.params.get('logger'):
|
if self.params.get('logger'):
|
||||||
self.params['logger'].debug(message)
|
self.params['logger'].debug(message)
|
||||||
elif not quiet or self.params.get('verbose'):
|
return
|
||||||
self._write_string(
|
if (self.params.get('quiet') if quiet is None else quiet) and not self.params.get('verbose'):
|
||||||
'%s%s' % (self._bidi_workaround(message), ('' if skip_eol else '\n')),
|
return
|
||||||
self._err_file if quiet else self._screen_file)
|
self._write_string(
|
||||||
|
'%s%s' % (self._bidi_workaround(message), ('' if skip_eol else '\n')),
|
||||||
|
self._out_files['screen'])
|
||||||
|
|
||||||
def to_stderr(self, message, only_once=False):
|
def to_stderr(self, message, only_once=False):
|
||||||
"""Print message to stderr"""
|
"""Print message to stderr"""
|
||||||
@ -803,7 +809,12 @@ class YoutubeDL(object):
|
|||||||
if self.params.get('logger'):
|
if self.params.get('logger'):
|
||||||
self.params['logger'].error(message)
|
self.params['logger'].error(message)
|
||||||
else:
|
else:
|
||||||
self._write_string('%s\n' % self._bidi_workaround(message), self._err_file, only_once=only_once)
|
self._write_string('%s\n' % self._bidi_workaround(message), self._out_files['error'], only_once=only_once)
|
||||||
|
|
||||||
|
def _send_console_code(self, code):
|
||||||
|
if compat_os_name == 'nt' or not self._out_files['console']:
|
||||||
|
return
|
||||||
|
self._write_string(code, self._out_files['console'])
|
||||||
|
|
||||||
def to_console_title(self, message):
|
def to_console_title(self, message):
|
||||||
if not self.params.get('consoletitle', False):
|
if not self.params.get('consoletitle', False):
|
||||||
@ -814,26 +825,18 @@ class YoutubeDL(object):
|
|||||||
# c_wchar_p() might not be necessary if `message` is
|
# c_wchar_p() might not be necessary if `message` is
|
||||||
# already of type unicode()
|
# already of type unicode()
|
||||||
ctypes.windll.kernel32.SetConsoleTitleW(ctypes.c_wchar_p(message))
|
ctypes.windll.kernel32.SetConsoleTitleW(ctypes.c_wchar_p(message))
|
||||||
elif 'TERM' in os.environ:
|
else:
|
||||||
self._write_string('\033]0;%s\007' % message, self._screen_file)
|
self._send_console_code(f'\033]0;{message}\007')
|
||||||
|
|
||||||
def save_console_title(self):
|
def save_console_title(self):
|
||||||
if not self.params.get('consoletitle', False):
|
if not self.params.get('consoletitle') or self.params.get('simulate'):
|
||||||
return
|
return
|
||||||
if self.params.get('simulate'):
|
self._send_console_code('\033[22;0t') # Save the title on stack
|
||||||
return
|
|
||||||
if compat_os_name != 'nt' and 'TERM' in os.environ:
|
|
||||||
# Save the title on stack
|
|
||||||
self._write_string('\033[22;0t', self._screen_file)
|
|
||||||
|
|
||||||
def restore_console_title(self):
|
def restore_console_title(self):
|
||||||
if not self.params.get('consoletitle', False):
|
if not self.params.get('consoletitle') or self.params.get('simulate'):
|
||||||
return
|
return
|
||||||
if self.params.get('simulate'):
|
self._send_console_code('\033[23;0t') # Restore the title from stack
|
||||||
return
|
|
||||||
if compat_os_name != 'nt' and 'TERM' in os.environ:
|
|
||||||
# Restore the title from stack
|
|
||||||
self._write_string('\033[23;0t', self._screen_file)
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.save_console_title()
|
self.save_console_title()
|
||||||
@ -879,11 +882,6 @@ class YoutubeDL(object):
|
|||||||
raise DownloadError(message, exc_info)
|
raise DownloadError(message, exc_info)
|
||||||
self._download_retcode = 1
|
self._download_retcode = 1
|
||||||
|
|
||||||
def to_screen(self, message, skip_eol=False):
|
|
||||||
"""Print message to stdout if not in quiet mode"""
|
|
||||||
self.to_stdout(
|
|
||||||
message, skip_eol, quiet=self.params.get('quiet', False))
|
|
||||||
|
|
||||||
class Styles(Enum):
|
class Styles(Enum):
|
||||||
HEADERS = 'yellow'
|
HEADERS = 'yellow'
|
||||||
EMPHASIS = 'light blue'
|
EMPHASIS = 'light blue'
|
||||||
@ -907,11 +905,11 @@ class YoutubeDL(object):
|
|||||||
|
|
||||||
def _format_screen(self, *args, **kwargs):
|
def _format_screen(self, *args, **kwargs):
|
||||||
return self._format_text(
|
return self._format_text(
|
||||||
self._screen_file, self._allow_colors['screen'], *args, **kwargs)
|
self._out_files['screen'], self._allow_colors['screen'], *args, **kwargs)
|
||||||
|
|
||||||
def _format_err(self, *args, **kwargs):
|
def _format_err(self, *args, **kwargs):
|
||||||
return self._format_text(
|
return self._format_text(
|
||||||
self._err_file, self._allow_colors['err'], *args, **kwargs)
|
self._out_files['error'], self._allow_colors['error'], *args, **kwargs)
|
||||||
|
|
||||||
def report_warning(self, message, only_once=False):
|
def report_warning(self, message, only_once=False):
|
||||||
'''
|
'''
|
||||||
@ -3604,7 +3602,7 @@ class YoutubeDL(object):
|
|||||||
encoding_str = 'Encodings: locale %s, fs %s, out %s, err %s, pref %s' % (
|
encoding_str = 'Encodings: locale %s, fs %s, out %s, err %s, pref %s' % (
|
||||||
locale.getpreferredencoding(),
|
locale.getpreferredencoding(),
|
||||||
sys.getfilesystemencoding(),
|
sys.getfilesystemencoding(),
|
||||||
get_encoding(self._screen_file), get_encoding(self._err_file),
|
get_encoding(self._out_files['screen']), get_encoding(self._out_files['error']),
|
||||||
self.get_encoding())
|
self.get_encoding())
|
||||||
|
|
||||||
logger = self.params.get('logger')
|
logger = self.params.get('logger')
|
||||||
|
@ -358,7 +358,6 @@ def validate_options(opts):
|
|||||||
raise ValueError('unsupported geo-bypass country or ip-block')
|
raise ValueError('unsupported geo-bypass country or ip-block')
|
||||||
|
|
||||||
opts.match_filter = match_filter_func(opts.match_filter)
|
opts.match_filter = match_filter_func(opts.match_filter)
|
||||||
opts.date = DateRange.day(opts.date) if opts.date else DateRange(opts.dateafter, opts.datebefore)
|
|
||||||
|
|
||||||
if opts.download_archive is not None:
|
if opts.download_archive is not None:
|
||||||
opts.download_archive = expand_path(opts.download_archive)
|
opts.download_archive = expand_path(opts.download_archive)
|
||||||
@ -406,8 +405,8 @@ def validate_options(opts):
|
|||||||
setattr(opts, opt1, default)
|
setattr(opts, opt1, default)
|
||||||
|
|
||||||
# Conflicting options
|
# Conflicting options
|
||||||
report_conflict('--date-after', 'dateafter', '--date', 'date', default=None)
|
report_conflict('--dateafter', 'dateafter', '--date', 'date', default=None)
|
||||||
report_conflict('--date-before', 'datebefore', '--date', 'date', default=None)
|
report_conflict('--datebefore', 'datebefore', '--date', 'date', default=None)
|
||||||
report_conflict('--exec-before-download', 'exec_before_dl_cmd', '"--exec before_dl:"', 'exec_cmd', opts.exec_cmd.get('before_dl'))
|
report_conflict('--exec-before-download', 'exec_before_dl_cmd', '"--exec before_dl:"', 'exec_cmd', 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')
|
||||||
@ -446,6 +445,8 @@ def validate_options(opts):
|
|||||||
# report_deprecation(opts.writeannotations, '--write-annotations') # It's just that no website has it
|
# 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)
|
||||||
|
|
||||||
if opts.exec_before_dl_cmd:
|
if opts.exec_before_dl_cmd:
|
||||||
opts.exec_cmd['before_dl'] = opts.exec_before_dl_cmd
|
opts.exec_cmd['before_dl'] = opts.exec_before_dl_cmd
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ class FileDownloader(object):
|
|||||||
return int(round(number * multiplier))
|
return int(round(number * multiplier))
|
||||||
|
|
||||||
def to_screen(self, *args, **kargs):
|
def to_screen(self, *args, **kargs):
|
||||||
self.ydl.to_stdout(*args, quiet=self.params.get('quiet'), **kargs)
|
self.ydl.to_screen(*args, quiet=self.params.get('quiet'), **kargs)
|
||||||
|
|
||||||
def to_stderr(self, message):
|
def to_stderr(self, message):
|
||||||
self.ydl.to_stderr(message)
|
self.ydl.to_stderr(message)
|
||||||
@ -277,9 +277,9 @@ class FileDownloader(object):
|
|||||||
elif self.ydl.params.get('logger'):
|
elif self.ydl.params.get('logger'):
|
||||||
self._multiline = MultilineLogger(self.ydl.params['logger'], lines)
|
self._multiline = MultilineLogger(self.ydl.params['logger'], lines)
|
||||||
elif self.params.get('progress_with_newline'):
|
elif self.params.get('progress_with_newline'):
|
||||||
self._multiline = BreaklineStatusPrinter(self.ydl._screen_file, lines)
|
self._multiline = BreaklineStatusPrinter(self.ydl._out_files['screen'], lines)
|
||||||
else:
|
else:
|
||||||
self._multiline = MultilinePrinter(self.ydl._screen_file, lines, not self.params.get('quiet'))
|
self._multiline = MultilinePrinter(self.ydl._out_files['screen'], lines, not self.params.get('quiet'))
|
||||||
self._multiline.allow_colors = self._multiline._HAVE_FULLCAP and not self.params.get('no_color')
|
self._multiline.allow_colors = self._multiline._HAVE_FULLCAP and not self.params.get('no_color')
|
||||||
|
|
||||||
def _finish_multiline_status(self):
|
def _finish_multiline_status(self):
|
||||||
|
@ -22,7 +22,7 @@ class YoutubeLiveChatFD(FragmentFD):
|
|||||||
def real_download(self, filename, info_dict):
|
def real_download(self, filename, info_dict):
|
||||||
video_id = info_dict['video_id']
|
video_id = info_dict['video_id']
|
||||||
self.to_screen('[%s] Downloading live chat' % self.FD_NAME)
|
self.to_screen('[%s] Downloading live chat' % self.FD_NAME)
|
||||||
if not self.params.get('skip_download'):
|
if not self.params.get('skip_download') and info_dict['protocol'] == 'youtube_live_chat':
|
||||||
self.report_warning('Live chat download runs until the livestream ends. '
|
self.report_warning('Live chat download runs until the livestream ends. '
|
||||||
'If you wish to download the video simultaneously, run a separate yt-dlp instance')
|
'If you wish to download the video simultaneously, run a separate yt-dlp instance')
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from .common import PostProcessor
|
from .common import PostProcessor
|
||||||
@ -26,12 +25,17 @@ class MetadataParserPP(PostProcessor):
|
|||||||
'''
|
'''
|
||||||
if not isinstance(action, cls.Actions):
|
if not isinstance(action, cls.Actions):
|
||||||
raise ValueError(f'{action!r} is not a valid action')
|
raise ValueError(f'{action!r} is not a valid action')
|
||||||
getattr(cls, action.value)(cls, *data)
|
getattr(cls, action.value)(cls, *data) # So this can raise error to validate
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def field_to_template(tmpl):
|
def field_to_template(tmpl):
|
||||||
if re.match(r'[a-zA-Z_]+$', tmpl):
|
if re.match(r'[a-zA-Z_]+$', tmpl):
|
||||||
return f'%({tmpl})s'
|
return f'%({tmpl})s'
|
||||||
|
|
||||||
|
from ..YoutubeDL import YoutubeDL
|
||||||
|
err = YoutubeDL.validate_outtmpl(tmpl)
|
||||||
|
if err:
|
||||||
|
raise err
|
||||||
return tmpl
|
return tmpl
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1029,7 +1029,7 @@ def make_HTTPS_handler(params, **kwargs):
|
|||||||
|
|
||||||
def bug_reports_message(before=';'):
|
def bug_reports_message(before=';'):
|
||||||
msg = ('please report this issue on https://github.com/yt-dlp/yt-dlp , '
|
msg = ('please report this issue on https://github.com/yt-dlp/yt-dlp , '
|
||||||
'filling out the "Broken site" issue template properly. '
|
'filling out the appropriate issue template. '
|
||||||
'Confirm you are on the latest version using yt-dlp -U')
|
'Confirm you are on the latest version using yt-dlp -U')
|
||||||
|
|
||||||
before = before.rstrip()
|
before = before.rstrip()
|
||||||
@ -5489,4 +5489,4 @@ has_websockets = bool(compat_websockets)
|
|||||||
|
|
||||||
def merge_headers(*dicts):
|
def merge_headers(*dicts):
|
||||||
"""Merge dicts of http headers case insensitively, prioritizing the latter ones"""
|
"""Merge dicts of http headers case insensitively, prioritizing the latter ones"""
|
||||||
return {k.capitalize(): v for k, v in itertools.chain.from_iterable(map(dict.items, dicts))}
|
return {k.title(): v for k, v in itertools.chain.from_iterable(map(dict.items, dicts))}
|
||||||
|
Loading…
Reference in New Issue
Block a user