mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-11-04 08:35:12 +00:00 
			
		
		
		
	
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							@@ -81,9 +81,9 @@ yt-dlp: yt_dlp/*.py yt_dlp/*/*.py
 | 
				
			|||||||
	  mkdir -p zip/$$d ;\
 | 
						  mkdir -p zip/$$d ;\
 | 
				
			||||||
	  cp -pPR $$d/*.py zip/$$d/ ;\
 | 
						  cp -pPR $$d/*.py zip/$$d/ ;\
 | 
				
			||||||
	done
 | 
						done
 | 
				
			||||||
	touch -t 200001010101 zip/yt_dlp/*.py zip/yt_dlp/*/*.py zip/yt_dlp/*/*/*.py
 | 
						touch -t 200001010101 zip/yt_dlp/*.py zip/yt_dlp/*/*.py
 | 
				
			||||||
	mv zip/yt_dlp/__main__.py zip/
 | 
						mv zip/yt_dlp/__main__.py zip/
 | 
				
			||||||
	cd zip ; zip -q ../yt-dlp yt_dlp/*.py yt_dlp/*/*.py yt_dlp/*/*/*.py __main__.py
 | 
						cd zip ; zip -q ../yt-dlp yt_dlp/*.py yt_dlp/*/*.py __main__.py
 | 
				
			||||||
	rm -rf zip
 | 
						rm -rf zip
 | 
				
			||||||
	echo '#!$(PYTHON)' > yt-dlp
 | 
						echo '#!$(PYTHON)' > yt-dlp
 | 
				
			||||||
	cat yt-dlp.zip >> yt-dlp
 | 
						cat yt-dlp.zip >> yt-dlp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2426,6 +2426,8 @@ class YoutubeDL:
 | 
				
			|||||||
            for key in live_keys:
 | 
					            for key in live_keys:
 | 
				
			||||||
                if info_dict.get(key) is None:
 | 
					                if info_dict.get(key) is None:
 | 
				
			||||||
                    info_dict[key] = (live_status == key)
 | 
					                    info_dict[key] = (live_status == key)
 | 
				
			||||||
 | 
					        if live_status == 'post_live':
 | 
				
			||||||
 | 
					            info_dict['was_live'] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Auto generate title fields corresponding to the *_number fields when missing
 | 
					        # Auto generate title fields corresponding to the *_number fields when missing
 | 
				
			||||||
        # in order to always have clean titles. This is very common for TV series.
 | 
					        # in order to always have clean titles. This is very common for TV series.
 | 
				
			||||||
@@ -3683,6 +3685,8 @@ class YoutubeDL:
 | 
				
			|||||||
        if not self.params.get('verbose'):
 | 
					        if not self.params.get('verbose'):
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        from . import _IN_CLI  # Must be delayed import
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # These imports can be slow. So import them only as needed
 | 
					        # These imports can be slow. So import them only as needed
 | 
				
			||||||
        from .extractor.extractors import _LAZY_LOADER
 | 
					        from .extractor.extractors import _LAZY_LOADER
 | 
				
			||||||
        from .extractor.extractors import _PLUGIN_CLASSES as plugin_extractors
 | 
					        from .extractor.extractors import _PLUGIN_CLASSES as plugin_extractors
 | 
				
			||||||
@@ -3719,6 +3723,7 @@ class YoutubeDL:
 | 
				
			|||||||
            __version__,
 | 
					            __version__,
 | 
				
			||||||
            f'[{RELEASE_GIT_HEAD}]' if RELEASE_GIT_HEAD else '',
 | 
					            f'[{RELEASE_GIT_HEAD}]' if RELEASE_GIT_HEAD else '',
 | 
				
			||||||
            '' if source == 'unknown' else f'({source})',
 | 
					            '' if source == 'unknown' else f'({source})',
 | 
				
			||||||
 | 
					            '' if _IN_CLI else 'API',
 | 
				
			||||||
            delim=' '))
 | 
					            delim=' '))
 | 
				
			||||||
        if not _LAZY_LOADER:
 | 
					        if not _LAZY_LOADER:
 | 
				
			||||||
            if os.environ.get('YTDLP_NO_LAZY_EXTRACTORS'):
 | 
					            if os.environ.get('YTDLP_NO_LAZY_EXTRACTORS'):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ from ..utils import (
 | 
				
			|||||||
    encodeFilename,
 | 
					    encodeFilename,
 | 
				
			||||||
    format_bytes,
 | 
					    format_bytes,
 | 
				
			||||||
    join_nonempty,
 | 
					    join_nonempty,
 | 
				
			||||||
 | 
					    remove_start,
 | 
				
			||||||
    sanitize_open,
 | 
					    sanitize_open,
 | 
				
			||||||
    shell_quote,
 | 
					    shell_quote,
 | 
				
			||||||
    timeconvert,
 | 
					    timeconvert,
 | 
				
			||||||
@@ -120,11 +121,11 @@ class FileDownloader:
 | 
				
			|||||||
        time = timetuple_from_msec(seconds * 1000)
 | 
					        time = timetuple_from_msec(seconds * 1000)
 | 
				
			||||||
        if time.hours > 99:
 | 
					        if time.hours > 99:
 | 
				
			||||||
            return '--:--:--'
 | 
					            return '--:--:--'
 | 
				
			||||||
        if not time.hours:
 | 
					 | 
				
			||||||
            return '   %02d:%02d' % time[1:-1]
 | 
					 | 
				
			||||||
        return '%02d:%02d:%02d' % time[:-1]
 | 
					        return '%02d:%02d:%02d' % time[:-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    format_eta = format_seconds
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def format_eta(cls, seconds):
 | 
				
			||||||
 | 
					        return f'{remove_start(cls.format_seconds(seconds), "00:"):>8s}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def calc_percent(byte_counter, data_len):
 | 
					    def calc_percent(byte_counter, data_len):
 | 
				
			||||||
@@ -332,6 +333,8 @@ class FileDownloader:
 | 
				
			|||||||
                    return tmpl
 | 
					                    return tmpl
 | 
				
			||||||
            return default
 | 
					            return default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _formats_bytes = lambda k: f'{format_bytes(s.get(k)):>10s}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if s['status'] == 'finished':
 | 
					        if s['status'] == 'finished':
 | 
				
			||||||
            if self.params.get('noprogress'):
 | 
					            if self.params.get('noprogress'):
 | 
				
			||||||
                self.to_screen('[download] Download completed')
 | 
					                self.to_screen('[download] Download completed')
 | 
				
			||||||
@@ -339,7 +342,7 @@ class FileDownloader:
 | 
				
			|||||||
            s.update({
 | 
					            s.update({
 | 
				
			||||||
                'speed': speed,
 | 
					                'speed': speed,
 | 
				
			||||||
                '_speed_str': self.format_speed(speed).strip(),
 | 
					                '_speed_str': self.format_speed(speed).strip(),
 | 
				
			||||||
                '_total_bytes_str': format_bytes(s.get('total_bytes')),
 | 
					                '_total_bytes_str': _formats_bytes('total_bytes'),
 | 
				
			||||||
                '_elapsed_str': self.format_seconds(s.get('elapsed')),
 | 
					                '_elapsed_str': self.format_seconds(s.get('elapsed')),
 | 
				
			||||||
                '_percent_str': self.format_percent(100),
 | 
					                '_percent_str': self.format_percent(100),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@@ -354,15 +357,15 @@ class FileDownloader:
 | 
				
			|||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        s.update({
 | 
					        s.update({
 | 
				
			||||||
            '_eta_str': self.format_eta(s.get('eta')),
 | 
					            '_eta_str': self.format_eta(s.get('eta')).strip(),
 | 
				
			||||||
            '_speed_str': self.format_speed(s.get('speed')),
 | 
					            '_speed_str': self.format_speed(s.get('speed')),
 | 
				
			||||||
            '_percent_str': self.format_percent(try_call(
 | 
					            '_percent_str': self.format_percent(try_call(
 | 
				
			||||||
                lambda: 100 * s['downloaded_bytes'] / s['total_bytes'],
 | 
					                lambda: 100 * s['downloaded_bytes'] / s['total_bytes'],
 | 
				
			||||||
                lambda: 100 * s['downloaded_bytes'] / s['total_bytes_estimate'],
 | 
					                lambda: 100 * s['downloaded_bytes'] / s['total_bytes_estimate'],
 | 
				
			||||||
                lambda: s['downloaded_bytes'] == 0 and 0)),
 | 
					                lambda: s['downloaded_bytes'] == 0 and 0)),
 | 
				
			||||||
            '_total_bytes_str': format_bytes(s.get('total_bytes')),
 | 
					            '_total_bytes_str': _formats_bytes('total_bytes'),
 | 
				
			||||||
            '_total_bytes_estimate_str': format_bytes(s.get('total_bytes_estimate')),
 | 
					            '_total_bytes_estimate_str': _formats_bytes('total_bytes_estimate'),
 | 
				
			||||||
            '_downloaded_bytes_str': format_bytes(s.get('downloaded_bytes')),
 | 
					            '_downloaded_bytes_str': _formats_bytes('downloaded_bytes'),
 | 
				
			||||||
            '_elapsed_str': self.format_seconds(s.get('elapsed')),
 | 
					            '_elapsed_str': self.format_seconds(s.get('elapsed')),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1862,7 +1862,7 @@ class InfoExtractor:
 | 
				
			|||||||
                    alias, field = field, self._get_field_setting(field, 'field')
 | 
					                    alias, field = field, self._get_field_setting(field, 'field')
 | 
				
			||||||
                    if self._get_field_setting(alias, 'deprecated'):
 | 
					                    if self._get_field_setting(alias, 'deprecated'):
 | 
				
			||||||
                        self.ydl.deprecated_feature(f'Format sorting alias {alias} is deprecated and may '
 | 
					                        self.ydl.deprecated_feature(f'Format sorting alias {alias} is deprecated and may '
 | 
				
			||||||
                                                    'be removed in a future version. Please use {field} instead')
 | 
					                                                    f'be removed in a future version. Please use {field} instead')
 | 
				
			||||||
                reverse = match.group('reverse') is not None
 | 
					                reverse = match.group('reverse') is not None
 | 
				
			||||||
                closest = match.group('separator') == '~'
 | 
					                closest = match.group('separator') == '~'
 | 
				
			||||||
                limit_text = match.group('limit')
 | 
					                limit_text = match.group('limit')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ from ..utils import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SpotifyBaseIE(InfoExtractor):
 | 
					class SpotifyBaseIE(InfoExtractor):
 | 
				
			||||||
 | 
					    _WORKING = False
 | 
				
			||||||
    _ACCESS_TOKEN = None
 | 
					    _ACCESS_TOKEN = None
 | 
				
			||||||
    _OPERATION_HASHES = {
 | 
					    _OPERATION_HASHES = {
 | 
				
			||||||
        'Episode': '8276d4423d709ae9b68ec1b74cc047ba0f7479059a37820be730f125189ac2bf',
 | 
					        'Episode': '8276d4423d709ae9b68ec1b74cc047ba0f7479059a37820be730f125189ac2bf',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -390,6 +390,8 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
 | 
				
			|||||||
        'si', 'th', 'lo', 'my', 'ka', 'am', 'km', 'zh-CN', 'zh-TW', 'zh-HK', 'ja', 'ko'
 | 
					        'si', 'th', 'lo', 'my', 'ka', 'am', 'km', 'zh-CN', 'zh-TW', 'zh-HK', 'ja', 'ko'
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _IGNORED_WARNINGS = {'Unavailable videos will be hidden during playback'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @functools.cached_property
 | 
					    @functools.cached_property
 | 
				
			||||||
    def _preferred_lang(self):
 | 
					    def _preferred_lang(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -692,12 +694,11 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
 | 
				
			|||||||
                    yield alert_type, message
 | 
					                    yield alert_type, message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _report_alerts(self, alerts, expected=True, fatal=True, only_once=False):
 | 
					    def _report_alerts(self, alerts, expected=True, fatal=True, only_once=False):
 | 
				
			||||||
        errors = []
 | 
					        errors, warnings = [], []
 | 
				
			||||||
        warnings = []
 | 
					 | 
				
			||||||
        for alert_type, alert_message in alerts:
 | 
					        for alert_type, alert_message in alerts:
 | 
				
			||||||
            if alert_type.lower() == 'error' and fatal:
 | 
					            if alert_type.lower() == 'error' and fatal:
 | 
				
			||||||
                errors.append([alert_type, alert_message])
 | 
					                errors.append([alert_type, alert_message])
 | 
				
			||||||
            else:
 | 
					            elif alert_message not in self._IGNORED_WARNINGS:
 | 
				
			||||||
                warnings.append([alert_type, alert_message])
 | 
					                warnings.append([alert_type, alert_message])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for alert_type, alert_message in (warnings + errors[:-1]):
 | 
					        for alert_type, alert_message in (warnings + errors[:-1]):
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user