diff --git a/dashboard/routes/discord.js b/dashboard/routes/discord.js
index 90568a3..45ce3fc 100644
--- a/dashboard/routes/discord.js
+++ b/dashboard/routes/discord.js
@@ -1,8 +1,7 @@
 const express = require("express"),
   router = express.Router();
 
-const fetch = require("node-fetch"),
-  btoa = require("btoa");
+const fetch = require("node-fetch")
 
 // Gets login page
 router.get("/login", async function (req, res) {
@@ -46,7 +45,7 @@ router.get("/callback", async (req, res) => {
     method: "POST",
     body: params.toString(),
     headers: {
-      Authorization: `Basic ${btoa(`${req.client.user.id}:${process.env.BOT_SECRET}`)}`,
+      Authorization: `Basic ${Buffer.from(`${req.client.user.id}:${process.env.BOT_SECRET}`).toString('base64')}`,
       "Content-Type": "application/x-www-form-urlencoded",
     },
   });
diff --git a/package-lock.json b/package-lock.json
index fc131be..3b511a1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,8 +15,6 @@
         "@lavaclient/spotify": "^3.1.0",
         "@lavaclient/types": "^2.1.1",
         "@vitalets/google-translate-api": "^9.2.0",
-        "ascii-table": "0.0.9",
-        "btoa": "^1.2.1",
         "common-tags": "^1.8.2",
         "connect-mongo": "^5.1.0",
         "country-emoji-languages": "^1.0.0",
@@ -35,8 +33,6 @@
         "moment": "^2.30.1",
         "mongoose": "^8.1.1",
         "nekos.life": "^3.0.0",
-        "node-fetch": "^2.7.0",
-        "os": "^0.1.2",
         "pino": "^8.18.0",
         "pino-pretty": "^10.3.1",
         "pretty-ms": "^7.0.1",
@@ -668,12 +664,6 @@
       "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
       "license": "MIT"
     },
-    "node_modules/ascii-table": {
-      "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/ascii-table/-/ascii-table-0.0.9.tgz",
-      "integrity": "sha512-xpkr6sCDIYTPqzvjG8M3ncw1YOTaloWZOyrUmicoEifBEKzQzt+ooUpRpQ/AbOoJfO/p2ZKiyp79qHThzJDulQ==",
-      "license": "MIT"
-    },
     "node_modules/asn1.js": {
       "version": "5.4.1",
       "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@@ -842,18 +832,6 @@
         "node": ">=16.20.1"
       }
     },
-    "node_modules/btoa": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
-      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
-      "license": "(MIT OR Apache-2.0)",
-      "bin": {
-        "btoa": "bin/btoa.js"
-      },
-      "engines": {
-        "node": ">= 0.4.0"
-      }
-    },
     "node_modules/buffer": {
       "version": "6.0.3",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -952,22 +930,6 @@
         "follow-redirects": "^1.15.6"
       }
     },
-    "node_modules/chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-      "license": "MIT",
-      "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
-      }
-    },
     "node_modules/chokidar": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1537,6 +1499,22 @@
         "url": "https://opencollective.com/eslint"
       }
     },
+    "node_modules/eslint/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
     "node_modules/espree": {
       "version": "9.6.1",
       "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -2122,7 +2100,6 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-      "license": "MIT",
       "engines": {
         "node": ">=8"
       }
@@ -2415,6 +2392,21 @@
         "node": ">=10"
       }
     },
+    "node_modules/jake/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
     "node_modules/joycon": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
@@ -3137,12 +3129,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/os": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/os/-/os-0.1.2.tgz",
-      "integrity": "sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==",
-      "license": "MIT"
-    },
     "node_modules/p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -4069,7 +4055,6 @@
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
       "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-      "license": "MIT",
       "dependencies": {
         "has-flag": "^4.0.0"
       },
diff --git a/package.json b/package.json
index 532f7cc..c017cd0 100644
--- a/package.json
+++ b/package.json
@@ -30,8 +30,6 @@
     "@lavaclient/spotify": "^3.1.0",
     "@lavaclient/types": "^2.1.1",
     "@vitalets/google-translate-api": "^9.2.0",
-    "ascii-table": "0.0.9",
-    "btoa": "^1.2.1",
     "common-tags": "^1.8.2",
     "connect-mongo": "^5.1.0",
     "country-emoji-languages": "^1.0.0",
@@ -50,8 +48,6 @@
     "moment": "^2.30.1",
     "mongoose": "^8.1.1",
     "nekos.life": "^3.0.0",
-    "node-fetch": "^2.7.0",
-    "os": "^0.1.2",
     "pino": "^8.18.0",
     "pino-pretty": "^10.3.1",
     "pretty-ms": "^7.0.1",
diff --git a/src/helpers/HttpUtils.js b/src/helpers/HttpUtils.js
index 95476af..88e1545 100644
--- a/src/helpers/HttpUtils.js
+++ b/src/helpers/HttpUtils.js
@@ -1,10 +1,35 @@
 const ISO6391 = require("iso-639-1");
 const sourcebin = require("sourcebin_js");
 const { error, debug } = require("@helpers/Logger");
-const fetch = require("node-fetch");
 const { translate: gTranslate } = require("@vitalets/google-translate-api");
+const Utils = require("./Utils");
 
 module.exports = class HttpUtils {
+  /**
+   * Asserts if response status is ok. Throws error if not
+   * @param { Response } res Response
+   */
+  static assertStatusOk(res) {
+    if (res.ok) return res
+    throw Error(`HTTP ${res.url} ${res.status} ${res.statusText}`)
+  }
+
+  /**
+   * Request with connection timeout
+   * @param {string | URL | Request} urlOrRequest
+   * @param {RequestInit} init
+   * @param {number} connTimeout
+   * @returns
+   */
+  static async fetchWithConnTimeout(urlOrRequest, init = {}, connTimeout) {
+    const abortCtrl = Utils.abortableSignal(connTimeout, () => new Error(`Connection timed out`))
+    init.signal = abortCtrl.signal
+
+    const res = await fetch(urlOrRequest, init)
+    abortCtrl()
+    return res
+  }
+
   /**
    * Returns JSON response from url
    * @param {string} url
diff --git a/src/helpers/Utils.js b/src/helpers/Utils.js
index c672261..57c4b28 100644
--- a/src/helpers/Utils.js
+++ b/src/helpers/Utils.js
@@ -4,6 +4,28 @@ const { join, extname } = require("path");
 const permissions = require("./permissions");
 
 module.exports = class Utils {
+  /**
+ * {@link setTimeout} but returns function that clears timeout when called
+ * @param {()=>void}fn Timeout function
+ * @param {number} timeout Timeout in millis
+ */
+  static abortable(timeout, fn) {
+    const id = setTimeout(fn, timeout)
+    return () => clearTimeout(id)
+  }
+  /**
+   * {@link AbortSignal.timeout} but can be aborted
+   * @param {()=>void}fn Timeout function
+   * @param {number} timeout Timeout in millis
+   */
+  static abortableSignal(timeout, fn) {
+    const ctrl = new AbortController
+    return Object.assign(
+      Utils.abortable(timeout, () => ctrl.abort(fn?.())),
+      { signal: ctrl.signal }
+    )
+  }
+
   /**
    * Checks if a string contains a URL
    * @param {string} text