]> jfr.im git - yt-dlp.git/blobdiff - yt_dlp/webvtt.py
[instagram] Add more formats when logged in (#1487)
[yt-dlp.git] / yt_dlp / webvtt.py
index 4d026834a2282c7fee2bee94fc1324e0426d0d7d..962aa57ad61e7db511a2253140b5860aac21e693 100644 (file)
@@ -13,7 +13,7 @@
 
 import re
 import io
-from .utils import int_or_none
+from .utils import int_or_none, timetuple_from_msec
 from .compat import (
     compat_str as str,
     compat_Pattern,
@@ -89,8 +89,12 @@ def __init__(self, parser):
         ))
 
 
+# While the specification <https://www.w3.org/TR/webvtt1/#webvtt-timestamp>
+# prescribes that hours must be *2 or more* digits, timestamps with a single
+# digit for the hour part has been seen in the wild.
+# See https://github.com/yt-dlp/yt-dlp/issues/921
 _REGEX_TS = re.compile(r'''(?x)
-    (?:([0-9]{2,}):)?
+    (?:([0-9]{1,}):)?
     ([0-9]{2}):
     ([0-9]{2})\.
     ([0-9]{3})?
@@ -120,12 +124,7 @@ def _format_ts(ts):
     Convert an MPEG PES timestamp into a WebVTT timestamp.
     This will lose sub-millisecond precision.
     """
-
-    ts = int((ts + 45) // 90)
-    ms , ts = divmod(ts, 1000)  # noqa: W504,E221,E222,E203
-    s  , ts = divmod(ts, 60)    # noqa: W504,E221,E222,E203
-    min, h  = divmod(ts, 60)    # noqa: W504,E221,E222
-    return '%02u:%02u:%02u.%03u' % (h, min, s, ms)
+    return '%02u:%02u:%02u.%03u' % timetuple_from_msec(int((ts + 45) // 90))
 
 
 class Block(object):
@@ -173,6 +172,7 @@ class Magic(HeaderBlock):
     _REGEX_TSMAP = re.compile(r'X-TIMESTAMP-MAP=')
     _REGEX_TSMAP_LOCAL = re.compile(r'LOCAL:')
     _REGEX_TSMAP_MPEGTS = re.compile(r'MPEGTS:([0-9]+)')
+    _REGEX_TSMAP_SEP = re.compile(r'[ \t]*,[ \t]*')
 
     @classmethod
     def __parse_tsmap(cls, parser):
@@ -195,7 +195,7 @@ def __parse_tsmap(cls, parser):
                         raise ParseError(parser)
                 else:
                     raise ParseError(parser)
-            if parser.consume(','):
+            if parser.consume(cls._REGEX_TSMAP_SEP):
                 continue
             if parser.consume(_REGEX_NL):
                 break
@@ -322,6 +322,36 @@ def write_into(self, stream):
         stream.write(self.text)
         stream.write('\n')
 
+    @property
+    def as_json(self):
+        return {
+            'id': self.id,
+            'start': self.start,
+            'end': self.end,
+            'text': self.text,
+            'settings': self.settings,
+        }
+
+    def __eq__(self, other):
+        return self.as_json == other.as_json
+
+    @classmethod
+    def from_json(cls, json):
+        return cls(
+            id=json['id'],
+            start=json['start'],
+            end=json['end'],
+            text=json['text'],
+            settings=json['settings']
+        )
+
+    def hinges(self, other):
+        if self.text != other.text:
+            return False
+        if self.settings != other.settings:
+            return False
+        return self.start <= self.end == other.start <= other.end
+
 
 def parse_fragment(frag_content):
     """