diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js
index 134dd4a7a43760f5c43911c2eb166c5cbdbd0028..f65aa87b3f4a51d0fdd18041d8ab36a12686d361 100644
--- a/app/src/main/assets/scripts/source.js
+++ b/app/src/main/assets/scripts/source.js
@@ -795,3 +795,99 @@ class URLSearchParams {
         return searchString;
     }
 }
+
+
+var __REGEX_SPACE_CHARACTERS = /<%= spaceCharacters %>/g;
+var __btoa_TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+function btoa(input) {
+	input = String(input);
+	if (/[^\0-\xFF]/.test(input)) {
+		// Note: no need to special-case astral symbols here, as surrogates are
+		// matched, and the input is supposed to only contain ASCII anyway.
+		error(
+			'The string to be encoded contains characters outside of the ' +
+			'Latin1 range.'
+		);
+	}
+	var padding = input.length % 3;
+	var output = '';
+	var position = -1;
+	var a;
+	var b;
+	var c;
+	var buffer;
+	// Make sure any padding is handled outside of the loop.
+	var length = input.length - padding;
+
+	while (++position < length) {
+		// Read three bytes, i.e. 24 bits.
+		a = input.charCodeAt(position) << 16;
+		b = input.charCodeAt(++position) << 8;
+		c = input.charCodeAt(++position);
+		buffer = a + b + c;
+		// Turn the 24 bits into four chunks of 6 bits each, and append the
+		// matching character for each of them to the output.
+		output += (
+			__btoa_TABLE.charAt(buffer >> 18 & 0x3F) +
+			__btoa_TABLE.charAt(buffer >> 12 & 0x3F) +
+			__btoa_TABLE.charAt(buffer >> 6 & 0x3F) +
+			__btoa_TABLE.charAt(buffer & 0x3F)
+		);
+	}
+
+	if (padding == 2) {
+		a = input.charCodeAt(position) << 8;
+		b = input.charCodeAt(++position);
+		buffer = a + b;
+		output += (
+			__btoa_TABLE.charAt(buffer >> 10) +
+			__btoa_TABLE.charAt((buffer >> 4) & 0x3F) +
+			__btoa_TABLE.charAt((buffer << 2) & 0x3F) +
+			'='
+		);
+	} else if (padding == 1) {
+		buffer = input.charCodeAt(position);
+		output += (
+			__btoa_TABLE.charAt(buffer >> 2) +
+			__btoa_TABLE.charAt((buffer << 4) & 0x3F) +
+			'=='
+		);
+	}
+
+	return output;
+};
+function atob(input) {
+	input = String(input)
+		.replace(__REGEX_SPACE_CHARACTERS, '');
+	var length = input.length;
+	if (length % 4 == 0) {
+		input = input.replace(/==?$/, '');
+		length = input.length;
+	}
+	if (
+		length % 4 == 1 ||
+		// http://whatwg.org/C#alphanumeric-ascii-characters
+		/[^+a-zA-Z0-9/]/.test(input)
+	) {
+		error(
+			'Invalid character: the string to be decoded is not correctly encoded.'
+		);
+	}
+	var bitCounter = 0;
+	var bitStorage;
+	var buffer;
+	var output = '';
+	var position = -1;
+	while (++position < length) {
+		buffer = __btoa_TABLE.indexOf(input.charAt(position));
+		bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
+		// Unless this is the first of a group of 4 characters…
+		if (bitCounter++ % 4) {
+			// …convert the first 8 bits to a single ASCII character.
+			output += String.fromCharCode(
+				0xFF & bitStorage >> (-2 * bitCounter & 6)
+			);
+		}
+	}
+	return output;
+};
diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
index 8535aafb79a1b6e7205da48ed18735589ba9d340..0020f249a86c3bee5cf41aa3db0e42d91e55baf8 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
@@ -99,6 +99,8 @@ class PackageHttp: V8Package {
 
         if(body is V8ValueString)
             return client.POST(url, body.value, headers, if(useByteResponse) ReturnType.BYTES else ReturnType.STRING);
+        else if(body is String)
+            return client.POST(url, body, headers, if(useByteResponse) ReturnType.BYTES else ReturnType.STRING);
         else if(body is V8ValueTypedArray)
             return client.POST(url, body.toBytes(), headers, if(useByteResponse) ReturnType.BYTES else ReturnType.STRING);
         else if(body is ByteArray)