aboutsummaryrefslogtreecommitdiff
path: root/yt_dlp/jsinterp.py
diff options
context:
space:
mode:
authorSimon Sawicki <contact@grub4k.xyz>2025-02-08 18:48:36 +0100
committerGitHub <noreply@github.com>2025-02-08 18:48:36 +0100
commit0d9f061d38c3a4da61972e2adad317079f2f1c84 (patch)
tree0ff1a9086dafda40ee62013aed2d19cd58017218 /yt_dlp/jsinterp.py
parent517ddf3c3f12560ab93e3d36244dc82db9f97818 (diff)
[jsinterp] Add `js_number_to_string` (#12110)
Authored by: Grub4K
Diffstat (limited to 'yt_dlp/jsinterp.py')
-rw-r--r--yt_dlp/jsinterp.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/yt_dlp/jsinterp.py b/yt_dlp/jsinterp.py
index ba059babb..bd6a47004 100644
--- a/yt_dlp/jsinterp.py
+++ b/yt_dlp/jsinterp.py
@@ -95,6 +95,61 @@ def _js_ternary(cndn, if_true=True, if_false=False):
return if_true
+# Ref: https://es5.github.io/#x9.8.1
+def js_number_to_string(val: float, radix: int = 10):
+ if radix in (JS_Undefined, None):
+ radix = 10
+ assert radix in range(2, 37), 'radix must be an integer at least 2 and no greater than 36'
+
+ if math.isnan(val):
+ return 'NaN'
+ if val == 0:
+ return '0'
+ if math.isinf(val):
+ return '-Infinity' if val < 0 else 'Infinity'
+ if radix == 10:
+ # TODO: implement special cases
+ ...
+
+ ALPHABET = b'0123456789abcdefghijklmnopqrstuvwxyz.-'
+
+ result = collections.deque()
+ sign = val < 0
+ val = abs(val)
+ fraction, integer = math.modf(val)
+ delta = max(math.nextafter(.0, math.inf), math.ulp(val) / 2)
+
+ if fraction >= delta:
+ result.append(-2) # `.`
+ while fraction >= delta:
+ delta *= radix
+ fraction, digit = math.modf(fraction * radix)
+ result.append(int(digit))
+ # if we need to round, propagate potential carry through fractional part
+ needs_rounding = fraction > 0.5 or (fraction == 0.5 and int(digit) & 1)
+ if needs_rounding and fraction + delta > 1:
+ for index in reversed(range(1, len(result))):
+ if result[index] + 1 < radix:
+ result[index] += 1
+ break
+ result.pop()
+
+ else:
+ integer += 1
+ break
+
+ integer, digit = divmod(int(integer), radix)
+ result.appendleft(digit)
+ while integer > 0:
+ integer, digit = divmod(integer, radix)
+ result.appendleft(digit)
+
+ if sign:
+ result.appendleft(-1) # `-`
+
+ return bytes(ALPHABET[digit] for digit in result).decode('ascii')
+
+
# Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
_OPERATORS = { # None => Defined in JSInterpreter._operator
'?': None,