|  | @@ -45,6 +45,7 @@ from .compat import (
 | 
	
		
			
				|  |  |      compat_casefold,
 | 
	
		
			
				|  |  |      compat_chr,
 | 
	
		
			
				|  |  |      compat_collections_abc,
 | 
	
		
			
				|  |  | +    compat_contextlib_suppress,
 | 
	
		
			
				|  |  |      compat_cookiejar,
 | 
	
		
			
				|  |  |      compat_ctypes_WINFUNCTYPE,
 | 
	
		
			
				|  |  |      compat_datetime_timedelta_total_seconds,
 | 
	
	
		
			
				|  | @@ -1855,25 +1856,18 @@ def write_json_file(obj, fn):
 | 
	
		
			
				|  |  |      try:
 | 
	
		
			
				|  |  |          with tf:
 | 
	
		
			
				|  |  |              json.dump(obj, tf)
 | 
	
		
			
				|  |  | -        if sys.platform == 'win32':
 | 
	
		
			
				|  |  | -            # Need to remove existing file on Windows, else os.rename raises
 | 
	
		
			
				|  |  | -            # WindowsError or FileExistsError.
 | 
	
		
			
				|  |  | -            try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(OSError):
 | 
	
		
			
				|  |  | +            if sys.platform == 'win32':
 | 
	
		
			
				|  |  | +                # Need to remove existing file on Windows, else os.rename raises
 | 
	
		
			
				|  |  | +                # WindowsError or FileExistsError.
 | 
	
		
			
				|  |  |                  os.unlink(fn)
 | 
	
		
			
				|  |  | -            except OSError:
 | 
	
		
			
				|  |  | -                pass
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  |              mask = os.umask(0)
 | 
	
		
			
				|  |  |              os.umask(mask)
 | 
	
		
			
				|  |  |              os.chmod(tf.name, 0o666 & ~mask)
 | 
	
		
			
				|  |  | -        except OSError:
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |          os.rename(tf.name, fn)
 | 
	
		
			
				|  |  |      except Exception:
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(OSError):
 | 
	
		
			
				|  |  |              os.remove(tf.name)
 | 
	
		
			
				|  |  | -        except OSError:
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |          raise
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2033,14 +2027,13 @@ def extract_attributes(html_element):
 | 
	
		
			
				|  |  |      NB HTMLParser is stricter in Python 2.6 & 3.2 than in later versions,
 | 
	
		
			
				|  |  |      but the cases in the unit test will work for all of 2.6, 2.7, 3.2-3.5.
 | 
	
		
			
				|  |  |      """
 | 
	
		
			
				|  |  | -    parser = HTMLAttributeParser()
 | 
	
		
			
				|  |  | -    try:
 | 
	
		
			
				|  |  | -        parser.feed(html_element)
 | 
	
		
			
				|  |  | -        parser.close()
 | 
	
		
			
				|  |  | -    # Older Python may throw HTMLParseError in case of malformed HTML
 | 
	
		
			
				|  |  | -    except compat_HTMLParseError:
 | 
	
		
			
				|  |  | -        pass
 | 
	
		
			
				|  |  | -    return parser.attrs
 | 
	
		
			
				|  |  | +    ret = None
 | 
	
		
			
				|  |  | +    # Older Python may throw HTMLParseError in case of malformed HTML (and on .close()!)
 | 
	
		
			
				|  |  | +    with compat_contextlib_suppress(compat_HTMLParseError):
 | 
	
		
			
				|  |  | +        with contextlib.closing(HTMLAttributeParser()) as parser:
 | 
	
		
			
				|  |  | +            parser.feed(html_element)
 | 
	
		
			
				|  |  | +            ret = parser.attrs
 | 
	
		
			
				|  |  | +    return ret or {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def clean_html(html):
 | 
	
	
		
			
				|  | @@ -2241,7 +2234,8 @@ def _htmlentity_transform(entity_with_semicolon):
 | 
	
		
			
				|  |  |              numstr = '0%s' % numstr
 | 
	
		
			
				|  |  |          else:
 | 
	
		
			
				|  |  |              base = 10
 | 
	
		
			
				|  |  | -        # See https://github.com/ytdl-org/youtube-dl/issues/7518
 | 
	
		
			
				|  |  | +        # See https://github.com/ytdl-org/youtube-dl/issues/7518\
 | 
	
		
			
				|  |  | +        # Also, weirdly, compat_contextlib_suppress fails here in 2.6
 | 
	
		
			
				|  |  |          try:
 | 
	
		
			
				|  |  |              return compat_chr(int(numstr, base))
 | 
	
		
			
				|  |  |          except ValueError:
 | 
	
	
		
			
				|  | @@ -2348,11 +2342,9 @@ def make_HTTPS_handler(params, **kwargs):
 | 
	
		
			
				|  |  |          # Some servers may (wrongly) reject requests if ALPN extension is not sent. See:
 | 
	
		
			
				|  |  |          # https://github.com/python/cpython/issues/85140
 | 
	
		
			
				|  |  |          # https://github.com/yt-dlp/yt-dlp/issues/3878
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(AttributeError, NotImplementedError):
 | 
	
		
			
				|  |  | +            # fails for Python < 2.7.10, not ssl.HAS_ALPN
 | 
	
		
			
				|  |  |              ctx.set_alpn_protocols(ALPN_PROTOCOLS)
 | 
	
		
			
				|  |  | -        except (AttributeError, NotImplementedError):
 | 
	
		
			
				|  |  | -            # Python < 2.7.10, not ssl.HAS_ALPN
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      opts_no_check_certificate = params.get('nocheckcertificate', False)
 | 
	
		
			
				|  |  |      if hasattr(ssl, 'create_default_context'):  # Python >= 3.4 or 2.7.9
 | 
	
	
		
			
				|  | @@ -2362,12 +2354,10 @@ def make_HTTPS_handler(params, **kwargs):
 | 
	
		
			
				|  |  |              context.check_hostname = False
 | 
	
		
			
				|  |  |              context.verify_mode = ssl.CERT_NONE
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(TypeError):
 | 
	
		
			
				|  |  | +            # Fails with Python 2.7.8 (create_default_context present
 | 
	
		
			
				|  |  | +            # but HTTPSHandler has no context=)
 | 
	
		
			
				|  |  |              return YoutubeDLHTTPSHandler(params, context=context, **kwargs)
 | 
	
		
			
				|  |  | -        except TypeError:
 | 
	
		
			
				|  |  | -            # Python 2.7.8
 | 
	
		
			
				|  |  | -            # (create_default_context present but HTTPSHandler has no context=)
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if sys.version_info < (3, 2):
 | 
	
		
			
				|  |  |          return YoutubeDLHTTPSHandler(params, **kwargs)
 | 
	
	
		
			
				|  | @@ -3176,12 +3166,10 @@ def parse_iso8601(date_str, delimiter='T', timezone=None):
 | 
	
		
			
				|  |  |      if timezone is None:
 | 
	
		
			
				|  |  |          timezone, date_str = extract_timezone(date_str)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    try:
 | 
	
		
			
				|  |  | +    with compat_contextlib_suppress(ValueError):
 | 
	
		
			
				|  |  |          date_format = '%Y-%m-%d{0}%H:%M:%S'.format(delimiter)
 | 
	
		
			
				|  |  |          dt = datetime.datetime.strptime(date_str, date_format) - timezone
 | 
	
		
			
				|  |  |          return calendar.timegm(dt.timetuple())
 | 
	
		
			
				|  |  | -    except ValueError:
 | 
	
		
			
				|  |  | -        pass
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def date_formats(day_first=True):
 | 
	
	
		
			
				|  | @@ -3201,17 +3189,13 @@ def unified_strdate(date_str, day_first=True):
 | 
	
		
			
				|  |  |      _, date_str = extract_timezone(date_str)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      for expression in date_formats(day_first):
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(ValueError):
 | 
	
		
			
				|  |  |              upload_date = datetime.datetime.strptime(date_str, expression).strftime('%Y%m%d')
 | 
	
		
			
				|  |  | -        except ValueError:
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |      if upload_date is None:
 | 
	
		
			
				|  |  |          timetuple = email.utils.parsedate_tz(date_str)
 | 
	
		
			
				|  |  |          if timetuple:
 | 
	
		
			
				|  |  | -            try:
 | 
	
		
			
				|  |  | +            with compat_contextlib_suppress(ValueError):
 | 
	
		
			
				|  |  |                  upload_date = datetime.datetime(*timetuple[:6]).strftime('%Y%m%d')
 | 
	
		
			
				|  |  | -            except ValueError:
 | 
	
		
			
				|  |  | -                pass
 | 
	
		
			
				|  |  |      if upload_date is not None:
 | 
	
		
			
				|  |  |          return compat_str(upload_date)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3240,11 +3224,9 @@ def unified_timestamp(date_str, day_first=True):
 | 
	
		
			
				|  |  |          date_str = m.group(1)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      for expression in date_formats(day_first):
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | +        with compat_contextlib_suppress(ValueError):
 | 
	
		
			
				|  |  |              dt = datetime.datetime.strptime(date_str, expression) - timezone + datetime.timedelta(hours=pm_delta)
 | 
	
		
			
				|  |  |              return calendar.timegm(dt.timetuple())
 | 
	
		
			
				|  |  | -        except ValueError:
 | 
	
		
			
				|  |  | -            pass
 | 
	
		
			
				|  |  |      timetuple = email.utils.parsedate_tz(date_str)
 | 
	
		
			
				|  |  |      if timetuple:
 | 
	
		
			
				|  |  |          return calendar.timegm(timetuple) + pm_delta * 3600 - compat_datetime_timedelta_total_seconds(timezone)
 |