Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package com.lagradost.cloudstream3.utils

import com.lagradost.cloudstream3.Prerelease
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.StringUtils.decodeUri
import com.lagradost.cloudstream3.utils.StringUtils.encodeUri
import kotlin.math.*
import kotlin.random.Random

/**
* Lightweight pure-Kotlin JavaScript interpreter designed to replace Rhino for
Expand Down Expand Up @@ -705,7 +708,7 @@ private class JsInterpreter {

private fun installGlobals() {
val mathObj = JsObject(mutableMapOf(
"PI" to Math.PI, "E" to Math.E,
"PI" to PI, "E" to E,
"floor" to nativeFn { args -> floor(toNumber(args.getOrNull(0))) },
"ceil" to nativeFn { args -> ceil(toNumber(args.getOrNull(0))) },
"round" to nativeFn { args -> round(toNumber(args.getOrNull(0))) },
Expand All @@ -718,7 +721,7 @@ private class JsInterpreter {
"tan" to nativeFn { args -> tan(toNumber(args.getOrNull(0))) },
"max" to nativeFn { args -> args.maxOfOrNull { toNumber(it) } ?: Double.NEGATIVE_INFINITY },
"min" to nativeFn { args -> args.minOfOrNull { toNumber(it) } ?: Double.POSITIVE_INFINITY },
"random" to nativeFn { _ -> Math.random() },
"random" to nativeFn { _ -> Random.nextDouble() },
"trunc" to nativeFn { args -> truncate(toNumber(args.getOrNull(0))) },
"log2" to nativeFn { args -> log2(toNumber(args.getOrNull(0))) },
"log10" to nativeFn { args -> log10(toNumber(args.getOrNull(0))) },
Expand All @@ -739,10 +742,10 @@ private class JsInterpreter {
globalScope.define("parseFloat", nativeFn { args -> toNumber(args.getOrNull(0)) })
globalScope.define("isNaN", nativeFn { args -> toNumber(args.getOrNull(0)).isNaN() })
globalScope.define("isFinite", nativeFn { args -> toNumber(args.getOrNull(0)).isFinite() })
globalScope.define("decodeURIComponent", nativeFn { args -> java.net.URLDecoder.decode(toJsString(args.getOrNull(0)), "UTF-8") })
globalScope.define("encodeURIComponent", nativeFn { args -> java.net.URLEncoder.encode(toJsString(args.getOrNull(0)), "UTF-8") })
globalScope.define("escape", nativeFn { args -> java.net.URLEncoder.encode(toJsString(args.getOrNull(0)), "UTF-8") })
globalScope.define("unescape", nativeFn { args -> java.net.URLDecoder.decode(toJsString(args.getOrNull(0)), "UTF-8") })
globalScope.define("decodeURIComponent", nativeFn { args -> toJsString(args.getOrNull(0)).decodeUri() })
globalScope.define("encodeURIComponent", nativeFn { args -> toJsString(args.getOrNull(0)).encodeUri() })
globalScope.define("escape", nativeFn { args -> toJsString(args.getOrNull(0)).encodeUri() })
globalScope.define("unescape", nativeFn { args -> toJsString(args.getOrNull(0)).decodeUri() })
globalScope.define("eval", nativeFn { args -> eval(toJsString(args.getOrNull(0))) })
globalScope.define("undefined", Unit)
globalScope.define("NaN", Double.NaN)
Expand Down Expand Up @@ -1188,8 +1191,15 @@ private class JsInterpreter {
if (radix == 10) toJsString(obj) else obj.toLong().toString(radix)
}
"toFixed" -> nativeFn { args ->
val digits = args.getOrNull(0)?.let { toNumber(it).toInt() } ?: 0
"%.${digits}f".format(obj)
val digits = (args.getOrNull(0)?.let { toNumber(it).toInt() } ?: 0).coerceIn(0, 20)
val factor = 10.0.pow(digits)
val rounded = round(obj * factor) / factor
val sign = if (rounded < 0) "-" else ""
val absVal = abs(rounded)
val intPart = absVal.toLong()
val fracPart = round((absVal - intPart) * factor).toLong()
val fracStr = fracPart.toString().padStart(digits, '0')
if (digits == 0) "$sign$intPart" else "$sign$intPart.$fracStr"
}
else -> Unit
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.lagradost.cloudstream3.utils

import kotlin.math.E
import kotlin.math.PI
import kotlin.math.abs
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -422,6 +424,41 @@ class JsInterpreterTest {
assertEquals("3.14", str("(3.14159).toFixed(2)"))
}

@Test
fun toFixedZeroDigits() {
assertEquals("4", str("(3.6).toFixed(0)"))
}

@Test
fun toFixedTwoDigits() {
assertEquals("3.14", str("(3.14159).toFixed(2)"))
}

@Test
fun toFixedPadsWithZeroes() {
assertEquals("3.10", str("(3.1).toFixed(2)"))
}

@Test
fun toFixedNegativeNumber() {
assertEquals("-3.14", str("(-3.14159).toFixed(2)"))
}

@Test
fun toFixedNegativeBetweenZeroAndMinusOne() {
assertEquals("-0.50", str("(-0.5).toFixed(2)"))
}

@Test
fun toFixedWholeNumber() {
assertEquals("5.00", str("(5).toFixed(2)"))
}

@Test
fun toFixedZeroValue() {
assertEquals("0.00", str("(0).toFixed(2)"))
}

@Test
fun arrayLiteralAndLength() {
assertEquals(3.0, num("[1,2,3].length"))
Expand Down Expand Up @@ -629,14 +666,46 @@ class JsInterpreterTest {

@Test
fun mathPi() {
assertApprox(Math.PI, num("Math.PI"))
assertApprox(PI, num("Math.PI"))
}

@Test
fun mathE() {
assertApprox(E, num("Math.E"))
}

@Test
fun mathLog() {
assertApprox(0.0, num("Math.log(1)"))
}

@Test
fun mathTruncPositive() {
assertEquals(3.0, num("Math.trunc(3.9)"))
}

@Test
fun mathTruncNegative() {
assertEquals(-3.0, num("Math.trunc(-3.9)"))
}

@Test
fun mathTruncZero() {
assertEquals(0.0, num("Math.trunc(0.5)"))
}

@Test
fun mathRandomInRange() {
val r = num("Math.random()")
assertTrue(r >= 0.0 && r < 1.0, "Math.random() should be in [0,1) but was $r")
}

@Test
fun mathRandomProducesDifferentValues() {
val results = (1..20).map { num("Math.random()") }.toSet()
assertTrue(results.size > 1, "Math.random() produced identical values across 20 calls")
}

@Test
fun parseIntDecimal() {
assertEquals(42.0, num("parseInt('42')"))
Expand Down