about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_locales/ar/messages.json2
-rw-r--r--src/_locales/de/messages.json2
-rw-r--r--src/_locales/en/messages.json2
-rw-r--r--src/_locales/es/messages.json2
-rw-r--r--src/_locales/fr/messages.json2
-rw-r--r--src/_locales/gl/messages.json2
-rw-r--r--src/_locales/id/messages.json2
-rw-r--r--src/_locales/it/messages.json2
-rw-r--r--src/_locales/ja/messages.json2
-rw-r--r--src/_locales/ko/messages.json2
-rw-r--r--src/_locales/nb_NO/messages.json2
-rw-r--r--src/_locales/nl/messages.json2
-rw-r--r--src/_locales/pl/messages.json2
-rw-r--r--src/_locales/pt_BR/messages.json2
-rw-r--r--src/_locales/ru/messages.json2
-rw-r--r--src/_locales/tr/messages.json2
-rw-r--r--src/assets/javascripts/frontend.js143
-rw-r--r--src/assets/javascripts/utils.js455
-rw-r--r--src/instances/blacklist.json14
-rw-r--r--src/instances/cloudtube.json4
-rw-r--r--src/instances/data.json153
-rw-r--r--src/instances/get_instances.py24
-rw-r--r--src/pages/background/background.js248
-rw-r--r--src/pages/errors/instance_offline.html5
-rw-r--r--src/pages/options/widgets/general.js3
25 files changed, 497 insertions, 584 deletions
diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json
index 4874ef15..86534b00 100644
--- a/src/_locales/ar/messages.json
+++ b/src/_locales/ar/messages.json
@@ -161,7 +161,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "هذا النظير غير متصل بالإنترنت، سيتم إعادة توجيهك بعد ",
+        "message": "هذا النظير غير متصل بالإنترنت، سيتم إعادة توجيهك بعد",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json
index 55bb0dc4..892918d3 100644
--- a/src/_locales/de/messages.json
+++ b/src/_locales/de/messages.json
@@ -206,7 +206,7 @@
         "message": "I2P"
     },
     "instanceOffline": {
-        "message": "Diese Instanz ist offline , du wirst weitergeleitet nach  "
+        "message": "Diese Instanz ist offline , du wirst weitergeleitet nach "
     },
     "testInstancesLatency": {
         "message": "Teste Latenz der Instanzen"
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 23d42e48..d4217ad9 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -175,7 +175,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "This instance is offline, you'll be redirected after ",
+        "message": "This instance is offline, you'll be redirected after",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json
index 07ea98c3..1998e799 100644
--- a/src/_locales/es/messages.json
+++ b/src/_locales/es/messages.json
@@ -107,7 +107,7 @@
         "message": "I2P"
     },
     "instanceOffline": {
-        "message": "Esta instancia está offline, serás redirigido/a luego de ",
+        "message": "Esta instancia está offline, serás redirigido/a luego de",
         "description": "used in instance_offline.html"
     },
     "testInstancesLatency": {
diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json
index c3234890..717ec8e1 100644
--- a/src/_locales/fr/messages.json
+++ b/src/_locales/fr/messages.json
@@ -139,7 +139,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Cette instance est hors ligne, vous serez redirigé après ",
+        "message": "Cette instance est hors ligne, vous serez redirigé après",
         "description": "used in instance_offline.html"
     },
     "settings": {
diff --git a/src/_locales/gl/messages.json b/src/_locales/gl/messages.json
index fba02255..a88810f6 100644
--- a/src/_locales/gl/messages.json
+++ b/src/_locales/gl/messages.json
@@ -196,7 +196,7 @@
         "message": "Esta interface non é totalmente privada."
     },
     "instanceOffline": {
-        "message": "Esta instancia está caída, ímoste redirixir após ",
+        "message": "Esta instancia está caída, ímoste redirixir após",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/id/messages.json b/src/_locales/id/messages.json
index 5e4d2b16..09ab8fe4 100644
--- a/src/_locales/id/messages.json
+++ b/src/_locales/id/messages.json
@@ -127,7 +127,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Instansi ini luring, Anda akan dialihkan setelah ",
+        "message": "Instansi ini luring, Anda akan dialihkan setelah",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json
index 9370f1a9..eab2d038 100644
--- a/src/_locales/it/messages.json
+++ b/src/_locales/it/messages.json
@@ -159,7 +159,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Questa istanza è offline, verrai reindirizzato tra ",
+        "message": "Questa istanza è offline, verrai reindirizzato tra",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json
index 32407e8d..bfae80c9 100644
--- a/src/_locales/ja/messages.json
+++ b/src/_locales/ja/messages.json
@@ -179,7 +179,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "このインスタンスはオフラインです。 ",
+        "message": "このインスタンスはオフラインです。",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/ko/messages.json b/src/_locales/ko/messages.json
index ad48864c..53cfcc13 100644
--- a/src/_locales/ko/messages.json
+++ b/src/_locales/ko/messages.json
@@ -115,7 +115,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "이 인스턴스는 오프라인입니다, 다음 초 후에 리다이렉트됩니다: ",
+        "message": "이 인스턴스는 오프라인입니다, 다음 초 후에 리다이렉트됩니다:",
         "description": "used in instance_offline.html"
     },
     "notFullyPrivate": {
diff --git a/src/_locales/nb_NO/messages.json b/src/_locales/nb_NO/messages.json
index 9a18930f..adae7e51 100644
--- a/src/_locales/nb_NO/messages.json
+++ b/src/_locales/nb_NO/messages.json
@@ -168,7 +168,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Denne instansen er nede. Du vil bli videresendt etter ",
+        "message": "Denne instansen er nede. Du vil bli videresendt etter",
         "description": "used in instance_offline.html"
     },
     "copyRaw": {
diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json
index fa223f60..e1c1ea17 100644
--- a/src/_locales/nl/messages.json
+++ b/src/_locales/nl/messages.json
@@ -173,7 +173,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Deze server is offline - je wordt doorgestuurd over ",
+        "message": "Deze server is offline - je wordt doorgestuurd over",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json
index 8ee06cc0..aed2eda5 100644
--- a/src/_locales/pl/messages.json
+++ b/src/_locales/pl/messages.json
@@ -100,7 +100,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Ta instancja jest offline, przekierowanie nastąpi po ",
+        "message": "Ta instancja jest offline, przekierowanie nastąpi po",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json
index 53b1de52..72729117 100644
--- a/src/_locales/pt_BR/messages.json
+++ b/src/_locales/pt_BR/messages.json
@@ -181,7 +181,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Esta instância está offline, você será redirecionado após ",
+        "message": "Esta instância está offline, você será redirecionado após",
         "description": "used in instance_offline.html"
     },
     "instanceIsOff": {
diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json
index 04afb07a..f48150fe 100644
--- a/src/_locales/ru/messages.json
+++ b/src/_locales/ru/messages.json
@@ -96,7 +96,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Этот экземпляр находится в автономном режиме, вы будете перенаправлены после ",
+        "message": "Этот экземпляр находится в автономном режиме, вы будете перенаправлены после",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json
index 8763af8f..fe434073 100644
--- a/src/_locales/tr/messages.json
+++ b/src/_locales/tr/messages.json
@@ -119,7 +119,7 @@
         "description": "used in the settings page"
     },
     "instanceOffline": {
-        "message": "Bu örnek çevrim dışı, yeniden yönlendirileceksiniz ",
+        "message": "Bu örnek çevrim dışı, yeniden yönlendirileceksiniz",
         "description": "used in instance_offline.html"
     },
     "cancel": {
diff --git a/src/assets/javascripts/frontend.js b/src/assets/javascripts/frontend.js
new file mode 100644
index 00000000..ab71cc0d
--- /dev/null
+++ b/src/assets/javascripts/frontend.js
@@ -0,0 +1,143 @@
+class FrontEnd {
+	constructor({ enable, frontends, frontend, redirect }) {
+		this.redirects = {}
+		this.enable = enable
+		this.frontend = frontend
+		this.protocol = "normal"
+		this.protocolFallback = true
+		fetch("/instances/data.json")
+			.then(response => response.text())
+			.then(async data => {
+				data = JSON.parse(data)
+				fetch("/instances/blacklist.json")
+					.then(response => response.text())
+					.then(async blackList => {
+						blackList = JSON.parse(blackList)
+						for (const frontend in frontends) {
+							this.redirects[frontend] = {}
+
+							this.redirects[frontend].cookies = [...frontends[frontend].cookies]
+
+							for (const protocol in data[frontend]) {
+								this.redirects[frontend][protocol] = {}
+
+								this.redirects[frontend][protocol].all = [...data[frontend][protocol]]
+
+								this.redirects[frontend][protocol].custom = []
+
+								this.redirects[frontend][protocol].checked = [...data[frontend][protocol]]
+								for (const instance of blackList.cloudflare) {
+									const a = this.redirects[frontend][protocol].checked.indexOf(instance)
+									if (a > -1) this.redirects[frontend][protocol].checked.splice(a, 1)
+								}
+								for (const instance of blackList.offline) {
+									const a = this.redirects[frontend][protocol].checked.indexOf(instance)
+									if (a > -1) this.redirects[frontend][protocol].checked.splice(a, 1)
+								}
+							}
+						}
+					})
+			})
+		this.unifyCookies = from =>
+			new Promise(async resolve => {
+				await init()
+				const protocolHost = utils.protocolHost(from)
+				const list = [...this.redirects[this.frontend][this.protocol]]
+				if (![...list.checked, ...list.custom].includes(protocolHost)) {
+					resolve()
+					return
+				}
+				for (const cookie of this.redirects[this.frontend].cookies) {
+					await utils.copyCookie(frontend, protocolHost, [...list.checked, list.custom], cookie)
+				}
+				resolve(true)
+			})
+
+		this.switchInstance = (url, disableOverride) => {
+			if (!this.enable && !disableOverride) return
+
+			const protocolHost = utils.protocolHost(url)
+
+			const list = [...this.redirects[this.frontend][this.protocol]]
+			if (!list.all.includes(protocolHost)) return
+
+			let userList = [...list.checked, ...list.custom]
+			if (userList.length === 0 && this.protocolFallback) userList = [...list.normal.all]
+
+			const i = userList.indexOf(protocolHost)
+			if (i > -1) userList.splice(i, 1)
+			if (userList.length === 0) return
+
+			const randomInstance = utils.getRandomInstance(userList)
+			return `${randomInstance}${url.pathname}${url.search}`
+		}
+
+		this.redirect = (url, type, initiator, disableOverride) => {
+			const result = redirect(url, type, initiator, disableOverride)
+			if (result == "BYPASSTAB") return "BYPASSTAB"
+			if (result) {
+				const list = [...this.redirects[this.frontend][this.protocol]]
+				let userList = [...list.checked, ...list.custom]
+				const randomInstance = utils.getRandomInstance(userList)
+				return `${randomInstance}${result.pathname}${result.search}`
+			}
+		}
+
+		let init = () => new Promise(async resolve => {})
+	}
+}
+
+let Reddit = new FrontEnd({
+	enable: true,
+	frontends: {
+		libreddit: { cookies: ["theme", "front_page", "layout", "wide", "post_sort", "comment_sort", "show_nsfw", "autoplay_videos", "use_hls", "hide_hls_notification", "subscriptions", "filters"] },
+		teddit: {
+			cookies: [
+				"collapse_child_comments",
+				"domain_instagram",
+				"domain_twitter",
+				"domain_youtube",
+				"flairs",
+				"highlight_controversial",
+				"nsfw_enabled",
+				"post_media_max_height",
+				"show_upvoted_percentage",
+				"show_upvotes",
+				"theme",
+				"videos_muted",
+			],
+		},
+	},
+	frontend: "libreddit",
+	redirect: (url, type, initiator, disableOverride) => {
+		if (this.enable && !disableOverride) return
+
+		const targets = [/^https?:\/{2}(www\.|old\.|np\.|new\.|amp\.|)reddit\.com/, /^https?:\/{2}(i\.|preview\.)redd\.it/]
+		if (!targets.some(rx => rx.test(url.href))) return
+
+		if (initiator && all().includes(initiator.origin)) return "BYPASSTAB"
+		if (!["main_frame", "xmlhttprequest", "other", "image", "media"].includes(type)) return
+
+		const bypassPaths = /\/(gallery\/poll\/rpan\/settings\/topics)/
+		if (url.pathname.match(bypassPaths)) return
+
+		const protocolHost = utils.protocolHost(url)
+
+		if (url.host === "i.redd.it") {
+			if (this.frontend == "libreddit") return `${protocolHost}/img${url.pathname}${url.search}`
+			if (this.frontend == "teddit") return `${protocolHost}/pics/w:null_${url.pathname.substring(1)}${url.search}`
+		} else if (url.host === "redd.it") {
+			// https://redd.it/foo => https://libredd.it/comments/foo
+			if (this.frontend == "libreddit" && !url.pathname.match(/^\/+[^\/]+\/+[^\/]/)) return `${protocolHost}/comments${url.pathname}${url.search}`
+			// https://redd.it/foo => https://teddit.net/comments/foo
+			if (this.frontend == "teddit" && !url.pathname.match(/^\/+[^\/]+\/+[^\/]/)) return `${protocolHost}/comments${url.pathname}${url.search}`
+		} else if (url.host === "preview.redd.it") {
+			if (this.frontend == "libreddit") return `${protocolHost}/preview/pre${url.pathname}${url.search}`
+			if (this.frontend == "teddit") return
+		} else {
+			return `${url.href}`
+		}
+	},
+})
+
+export default {}
diff --git a/src/assets/javascripts/utils.js b/src/assets/javascripts/utils.js
deleted file mode 100644
index 9ae9123f..00000000
--- a/src/assets/javascripts/utils.js
+++ /dev/null
@@ -1,455 +0,0 @@
-window.browser = window.browser || window.chrome
-
-import localise from "./localise.js"
-import servicesHelper from "./services.js"
-
-function getRandomInstance(instances) {
-	return instances[~~(instances.length * Math.random())]
-}
-
-function camelCase(str) {
-	return str.charAt(0).toUpperCase() + str.slice(1)
-}
-
-let cloudflareBlackList = []
-let authenticateBlackList = []
-let offlineBlackList = []
-async function initBlackList() {
-	return new Promise(resolve => {
-		fetch("/instances/blacklist.json")
-			.then(response => response.text())
-			.then(data => {
-				cloudflareBlackList = JSON.parse(data).cloudflare
-				authenticateBlackList = JSON.parse(data).authenticate
-				offlineBlackList = JSON.parse(data).offline
-				resolve()
-			})
-	})
-}
-
-function updateInstances() {
-	return new Promise(async resolve => {
-		let http = new XMLHttpRequest()
-		let fallback = new XMLHttpRequest()
-		http.open("GET", "https://codeberg.org/LibRedirect/libredirect/raw/branch/master/src/instances/data.json", false)
-		http.send(null)
-		if (http.status != 200) {
-			fallback.open("GET", "https://raw.githubusercontent.com/libredirect/libredirect/master/src/instances/data.json", false)
-			fallback.send(null)
-			if (fallback.status === 200) {
-				http = fallback
-			} else {
-				resolve()
-				return
-			}
-		}
-		await initBlackList()
-		const instances = JSON.parse(http.responseText)
-
-		servicesHelper.setRedirects(instances)
-
-		console.info("Successfully updated Instances")
-		resolve(true)
-		return
-	})
-}
-
-function protocolHost(url) {
-	if (url.username && url.password) return `${url.protocol}//${url.username}:${url.password}@${url.host}`
-	return `${url.protocol}//${url.host}`
-}
-
-async function processDefaultCustomInstances(service, frontend, network, document) {
-	let instancesLatency
-	let frontendNetworkElement = document.getElementById(frontend).getElementsByClassName(network)[0]
-
-	let frontendCustomInstances = []
-	let frontendCheckListElement = frontendNetworkElement.getElementsByClassName("checklist")[0]
-
-	await initBlackList()
-
-	let frontendDefaultRedirects
-
-	let redirects, options
-
-	async function getFromStorage() {
-		return new Promise(async resolve =>
-			browser.storage.local.get(["options", "redirects", "latency"], r => {
-				frontendDefaultRedirects = r.options[frontend][network].enabled
-				frontendCustomInstances = r.options[frontend][network].custom
-				options = r.options
-				instancesLatency = r.latency[frontend] ?? []
-				redirects = r.redirects
-				resolve()
-			})
-		)
-	}
-
-	await getFromStorage()
-
-	function calcFrontendCheckBoxes() {
-		let isTrue = true
-		for (const item of redirects[frontend][network]) {
-			if (!frontendDefaultRedirects.includes(item)) {
-				isTrue = false
-				break
-			}
-		}
-		for (const element of frontendCheckListElement.getElementsByTagName("input")) {
-			element.checked = frontendDefaultRedirects.includes(element.className)
-		}
-		if (frontendDefaultRedirects.length == 0) isTrue = false
-		frontendNetworkElement.getElementsByClassName("toggle-all")[0].checked = isTrue
-	}
-	frontendCheckListElement.innerHTML = [
-		`<div>
-        <x data-localise="__MSG_toggleAll__">Toggle All</x>
-        <input type="checkbox" class="toggle-all"/>
-      </div>`,
-		...redirects[frontend][network].map(x => {
-			const cloudflare = cloudflareBlackList.includes(x) ? ' <span style="color:red;">cloudflare</span>' : ""
-			const authenticate = authenticateBlackList.includes(x) ? ' <span style="color:orange;">authenticate</span>' : ""
-			const offline = offlineBlackList.includes(x) ? ' <span style="color:grey;">offline</span>' : ""
-
-			let ms = instancesLatency[x]
-			let latencyColor = ms == -1 ? "red" : ms <= 1000 ? "green" : ms <= 2000 ? "orange" : "red"
-			let latencyLimit
-			if (ms == 5000) latencyLimit = "5000ms+"
-			else if (ms > 5000) latencyLimit = `ERROR: ${ms - 5000}`
-			else if (ms == -1) latencyLimit = "Server not found"
-			else latencyLimit = ms + "ms"
-
-			const latency = x in instancesLatency ? '<span style="color:' + latencyColor + ';">' + latencyLimit + "</span>" : ""
-
-			let warnings = [cloudflare, authenticate, offline, latency].join(" ")
-			return `<div>
-                    <x><a href="${x}" target="_blank">${x}</a>${warnings}</x>
-                    <input type="checkbox" class="${x}"/>
-                  </div>`
-		}),
-	].join("\n<hr>\n")
-
-	localise.localisePage()
-
-	calcFrontendCheckBoxes()
-	frontendNetworkElement.getElementsByClassName("toggle-all")[0].addEventListener("change", async event => {
-		if (event.target.checked) frontendDefaultRedirects = [...redirects[frontend][network]]
-		else frontendDefaultRedirects = []
-
-		options[frontend][network].enabled = frontendDefaultRedirects
-		browser.storage.local.set({ options })
-		calcFrontendCheckBoxes()
-	})
-
-	for (let element of frontendCheckListElement.getElementsByTagName("input")) {
-		if (element.className != "toggle-all")
-			frontendNetworkElement.getElementsByClassName(element.className)[0].addEventListener("change", async event => {
-				if (event.target.checked) frontendDefaultRedirects.push(element.className)
-				else {
-					let index = frontendDefaultRedirects.indexOf(element.className)
-					if (index > -1) frontendDefaultRedirects.splice(index, 1)
-				}
-
-				options[frontend][network].enabled = frontendDefaultRedirects
-				browser.storage.local.set({ options })
-				calcFrontendCheckBoxes()
-			})
-	}
-
-	function calcFrontendCustomInstances() {
-		frontendNetworkElement.getElementsByClassName("custom-checklist")[0].innerHTML = frontendCustomInstances
-			.map(
-				x => `<div>
-                ${x}
-                <button class="add clear-${x}">
-                  <svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 24 24" width="20px" fill="currentColor">
-                    <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
-                  </svg>
-                </button>
-              </div>
-              <hr>`
-			)
-			.join("\n")
-
-		for (const item of frontendCustomInstances) {
-			frontendNetworkElement.getElementsByClassName(`clear-${item}`)[0].addEventListener("click", async () => {
-				let index = frontendCustomInstances.indexOf(item)
-				if (index > -1) frontendCustomInstances.splice(index, 1)
-				options[frontend][network].custom = frontendCustomInstances
-				browser.storage.local.set({ options })
-				calcFrontendCustomInstances()
-			})
-		}
-	}
-	calcFrontendCustomInstances()
-	frontendNetworkElement.getElementsByClassName("custom-instance-form")[0].addEventListener("submit", async event => {
-		event.preventDefault()
-		let frontendCustomInstanceInput = frontendNetworkElement.getElementsByClassName("custom-instance")[0]
-		let url = new URL(frontendCustomInstanceInput.value)
-		let protocolHostVar = protocolHost(url)
-		if (frontendCustomInstanceInput.validity.valid && !redirects[frontend][network].includes(protocolHostVar)) {
-			if (!frontendCustomInstances.includes(protocolHostVar)) {
-				frontendCustomInstances.push(protocolHostVar)
-				options[frontend][network].custom = frontendCustomInstances
-				browser.storage.local.set({ options })
-				frontendCustomInstanceInput.value = ""
-			}
-			calcFrontendCustomInstances()
-		}
-	})
-}
-
-function ping(href) {
-	return new Promise(async resolve => {
-		let average = 0
-		let time
-		for (let i = 0; i < 3; i++) {
-			time = await pingOnce(href)
-			if (i == 0) continue
-			if (time >= 5000) {
-				resolve(time)
-				return
-			}
-			average += time
-		}
-		average = parseInt(average / 3)
-		resolve(average)
-	})
-}
-
-function pingOnce(href) {
-	return new Promise(async resolve => {
-		let started
-		let http = new XMLHttpRequest()
-		http.timeout = 5000
-		http.ontimeout = () => resolve(5000)
-		http.onerror = () => resolve()
-		http.onreadystatechange = () => {
-			if (http.readyState == 2) {
-				if (http.status == 200) {
-					let ended = new Date().getTime()
-					http.abort()
-					resolve(ended - started)
-				} else {
-					resolve(5000 + http.status)
-				}
-			}
-		}
-		http.open("GET", `${href}?_=${new Date().getTime()}`, true)
-		started = new Date().getTime()
-		http.send(null)
-	})
-}
-
-async function testLatency(element, instances, frontend) {
-	return new Promise(async resolve => {
-		let myList = {}
-		let latencyThreshold, options
-		browser.storage.local.get(["options"], r => {
-			latencyThreshold = r.options.latencyThreshold
-			options = r.options
-		})
-		for (const href of instances) {
-			await ping(href).then(time => {
-				let color
-				if (time) {
-					myList[href] = time
-					if (time <= 1000) color = "green"
-					else if (time <= 2000) color = "orange"
-					else color = "red"
-
-					if (time > latencyThreshold && options[frontend].clearnet.enabled.includes(href)) {
-						options[frontend].clearnet.enabled.splice(options[frontend].clearnet.enabled.indexOf(href), 1)
-					}
-
-					let text
-					if (time == 5000) text = "5000ms+"
-					else if (time > 5000) text = `ERROR: ${time - 5000}`
-					else text = `${time}ms`
-					element.innerHTML = `${href}:&nbsp;<span style="color:${color};">${text}</span>`
-				} else {
-					myList[href] = -1
-					color = "red"
-					element.innerHTML = `${href}:&nbsp;<span style="color:${color};">Server not found</span>`
-					if (options[frontend].clearnet.enabled.includes(href)) options[frontend].clearnet.enabled.splice(options[frontend].clearnet.enabled.indexOf(href), 1)
-				}
-			})
-		}
-		browser.storage.local.set({ options })
-		resolve(myList)
-	})
-}
-
-function copyCookie(frontend, targetUrl, urls, name) {
-	return new Promise(resolve => {
-		browser.storage.local.get("options", r => {
-			let query
-			if (!r.options.firstPartyIsolate)
-				query = {
-					url: protocolHost(targetUrl),
-					name: name,
-				}
-			else
-				query = {
-					url: protocolHost(targetUrl),
-					name: name,
-					firstPartyDomain: null,
-				}
-			browser.cookies.getAll(query, async cookies => {
-				for (const cookie of cookies)
-					if (cookie.name == name) {
-						for (const url of urls) {
-							const setQuery = r.options.firstPartyIsolate
-								? {
-										url: url,
-										name: name,
-										value: cookie.value,
-										secure: true,
-										firstPartyDomain: new URL(url).hostname,
-								  }
-								: {
-										url: url,
-										name: name,
-										value: cookie.value,
-										secure: true,
-										expirationDate: cookie.expirationDate,
-								  }
-							browser.cookies.set(setQuery)
-						}
-						break
-					}
-				resolve()
-			})
-		})
-	})
-}
-
-function getPreferencesFromToken(frontend, targetUrl, urls, name, endpoint) {
-	return new Promise(resolve => {
-		const http = new XMLHttpRequest()
-		const url = `${targetUrl}${endpoint}`
-		http.open("GET", url, false)
-		//http.setRequestHeader("Cookie", `${name}=${cookie.value}`)
-		http.send(null)
-		const preferences = JSON.parse(http.responseText)
-		let formdata = new FormData()
-		for (var key in preferences) formdata.append(key, preferences[key])
-		for (const url of urls) {
-			const http = new XMLHttpRequest()
-			http.open("POST", `${url}/settings/stay`, false)
-			http.send(null)
-		}
-		resolve()
-		return
-	})
-}
-
-function copyRaw(test, copyRawElement) {
-	return new Promise(resolve => {
-		browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
-			let currTab = tabs[0]
-			if (currTab) {
-				let url
-				try {
-					url = new URL(currTab.url)
-				} catch {
-					resolve()
-					return
-				}
-
-				const newUrl = await servicesHelper.reverse(url)
-
-				if (newUrl) {
-					resolve(newUrl)
-					if (test) return
-					navigator.clipboard.writeText(newUrl)
-					if (copyRawElement) {
-						const textElement = copyRawElement.getElementsByTagName("h4")[0]
-						const oldHtml = textElement.innerHTML
-						textElement.innerHTML = browser.i18n.getMessage("copied")
-						setTimeout(() => (textElement.innerHTML = oldHtml), 1000)
-					}
-				}
-			}
-			resolve()
-		})
-	})
-}
-
-function unify() {
-	return new Promise(resolve => {
-		browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
-			let currTab = tabs[0]
-			if (currTab) {
-				let url
-				try {
-					url = new URL(currTab.url)
-				} catch {
-					resolve()
-					return
-				}
-
-				resolve(await servicesHelper.unifyPreferences(url, currTab.id))
-			}
-		})
-	})
-}
-
-function switchInstance(test) {
-	return new Promise(resolve => {
-		browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
-			let currTab = tabs[0]
-			if (currTab) {
-				let url
-				try {
-					url = new URL(currTab.url)
-				} catch {
-					resolve()
-					return
-				}
-				const newUrl = await servicesHelper.switchInstance(url)
-
-				if (newUrl) {
-					if (!test) browser.tabs.update({ url: newUrl })
-					resolve(true)
-				} else resolve()
-			}
-		})
-	})
-}
-
-function latency(service, frontend, document, location) {
-	let latencyElement = document.getElementById(`latency-${frontend}`)
-	let latencyLabel = document.getElementById(`latency-${frontend}-label`)
-	latencyElement.addEventListener("click", async () => {
-		let reloadWindow = () => location.reload()
-		latencyElement.addEventListener("click", reloadWindow)
-		browser.storage.local.get(["redirects", "latency"], r => {
-			let redirects = r.redirects
-			let latency = r.latency
-			const oldHtml = latencyLabel.innerHTML
-			latencyLabel.innerHTML = "..."
-			testLatency(latencyLabel, redirects[frontend].clearnet, frontend).then(r => {
-				latency[frontend] = r
-				browser.storage.local.set({ latency })
-				latencyLabel.innerHTML = oldHtml
-				processDefaultCustomInstances(service, frontend, "clearnet", document)
-				latencyElement.removeEventListener("click", reloadWindow)
-			})
-		})
-	})
-}
-
-export default {
-	getRandomInstance,
-	updateInstances,
-	protocolHost,
-	processDefaultCustomInstances,
-	latency,
-	copyCookie,
-	getPreferencesFromToken,
-	switchInstance,
-	copyRaw,
-	unify,
-	camelCase,
-}
diff --git a/src/instances/blacklist.json b/src/instances/blacklist.json
index fe941df0..edce1958 100644
--- a/src/instances/blacklist.json
+++ b/src/instances/blacklist.json
@@ -11,10 +11,8 @@
     "https://watch.whatever.social",
     "https://piped.garudalinux.org",
     "https://y.rivo.lol",
-    "https://cringe.whatever.social",
     "https://nitter.domain.glass",
     "https://birdsite.xanny.family",
-    "https://nitter.it",
     "https://notabird.site",
     "https://fuckthesacklers.network",
     "https://nitter.winscloud.net",
@@ -29,6 +27,7 @@
     "https://nitter.sneed.network",
     "https://n.sneed.network",
     "https://nitter.twei.space",
+    "https://nitter.d420.de",
     "https://libreddit.domain.glass",
     "https://r.nf",
     "https://libreddit.hu",
@@ -39,7 +38,6 @@
     "https://libreddit.winscloud.net",
     "https://r.ahwx.org",
     "https://reddit.dr460nf1r3.org",
-    "https://libreddit.mha.fi",
     "https://libreddit.encrypted-data.xyz",
     "https://libreddit.eu.org",
     "https://teddit.domain.glass",
@@ -72,15 +70,13 @@
     "https://invidious.rhyshl.live",
     "https://proxitok.odyssey346.dev",
     "https://nhanh.cloud",
-    "https://nitter.nl",
+    "https://nitter.winscloud.net",
     "https://ntr.odyssey346.dev",
-    "https://libreddit.nl",
+    "https://libreddit.yonalee.eu",
+    "https://libreddit.winscloud.net",
     "https://libreddit.notyourcomputer.net",
     "https://teddit.ggc-project.de",
-    "https://teddit.nautolan.racing",
-    "https://tedd.it",
-    "https://teddit.artemislena.eu",
-    "https://wiki.froth.zone",
+    "https://teddit.tokhmi.xyz",
     "https://quetre.odyssey346.dev",
     "https://st.odyssey346.dev",
     "https://jsearch.pw",
diff --git a/src/instances/cloudtube.json b/src/instances/cloudtube.json
index caba9d9c..8742d09c 100644
--- a/src/instances/cloudtube.json
+++ b/src/instances/cloudtube.json
@@ -1,6 +1,6 @@
 {
-	"clearnet": ["https://tube.cadence.moe", "https://yt.beparanoid.de"],
-	"tor": ["http://yt.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion"],
+	"clearnet": ["https://tube.cadence.moe"],
+	"tor": [],
 	"i2p": [],
 	"loki": []
 }
diff --git a/src/instances/data.json b/src/instances/data.json
index e2e5d9f5..839b155b 100644
--- a/src/instances/data.json
+++ b/src/instances/data.json
@@ -6,35 +6,35 @@
       "https://invidious.snopyta.org",
       "https://invidious.kavin.rocks",
       "https://inv.riverside.rocks",
-      "https://invidio.xamh.de",
       "https://y.com.sb",
       "https://yt.artemislena.eu",
-      "https://invidious.sethforprivacy.com",
-      "https://invidious.flokinet.to",
       "https://invidious.tiekoetter.com",
+      "https://invidious.flokinet.to",
       "https://inv.bp.projectsegfau.lt",
       "https://inv.vern.cc",
-      "https://invidious.projectsegfau.lt",
       "https://invidious.nerdvpn.de",
+      "https://invidious.projectsegfau.lt",
       "https://invidious.rhyshl.live",
       "https://inv.privacy.com.de",
       "https://invidious.slipfox.xyz",
-      "https://invidious.weblibre.org",
       "https://invidious.esmailelbob.xyz",
       "https://youtube.076.ne.jp",
-      "https://invidious.namazso.eu"
+      "https://invidious.sethforprivacy.com",
+      "https://invidious.namazso.eu",
+      "https://invidio.xamh.de"
     ],
     "tor": [
-      "http://inv.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion",
-      "http://invidious.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion",
-      "http://euxxcnhsynwmfidvhjf6uzptsmh4dipkmgdmcmxxuo7tunp3ad2jrwyd.onion",
-      "http://u2cvlit75owumwpy4dj2hsmvkq7nvrclkpht7xgyye2pyoxhpmclkrad.onion",
-      "http://osbivz6guyeahrwp2lnwyjk2xos342h4ocsxyqrlaopqjuhwn2djiiyd.onion",
-      "http://grwp24hodrefzvjjuccrkw3mjq4tzhaaq32amf33dzpmuxe7ilepcmad.onion",
-      "http://kbjggqkzv65ivcqj6bumvp337z6264huv5kpkwuv6gu5yjiskvan7fad.onion",
-      "http://w6ijuptxiku4xpnnaetxvnkc5vqcdu7mgns2u77qefoixi63vbvnpnqd.onion",
       "http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion",
-      "http://am74vkcrjp2d5v36lcdqgsj2m6x36tbrkhsruoegwfcizzabnfgf5zyd.onion"
+      "http://kbjggqkzv65ivcqj6bumvp337z6264huv5kpkwuv6gu5yjiskvan7fad.onion",
+      "http://grwp24hodrefzvjjuccrkw3mjq4tzhaaq32amf33dzpmuxe7ilepcmad.onion",
+      "http://osbivz6guyeahrwp2lnwyjk2xos342h4ocsxyqrlaopqjuhwn2djiiyd.onion",
+      "http://u2cvlit75owumwpy4dj2hsmvkq7nvrclkpht7xgyye2pyoxhpmclkrad.onion",
+      "http://euxxcnhsynwmfidvhjf6uzptsmh4dipkmgdmcmxxuo7tunp3ad2jrwyd.onion",
+      "http://invidious.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion",
+      "http://inv.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion",
+      "http://am74vkcrjp2d5v36lcdqgsj2m6x36tbrkhsruoegwfcizzabnfgf5zyd.onion",
+      "http://ng27owmagn5amdm7l5s3rsqxwscl5ynppnis5dqcasogkyxcfqn7psid.onion",
+      "http://w6ijuptxiku4xpnnaetxvnkc5vqcdu7mgns2u77qefoixi63vbvnpnqd.onion"
     ],
     "i2p": [],
     "loki": []
@@ -53,14 +53,13 @@
       "https://yt.jae.fi",
       "https://piped.mint.lgbt",
       "https://il.ax",
-      "https://piped.privacy.com.de",
       "https://piped.esmailelbob.xyz",
       "https://piped.projectsegfau.lt",
       "https://piped.privacydev.net",
-      "https://piped.palveluntarjoaja.eu",
       "https://piped.smnz.de",
       "https://piped.adminforge.de",
-      "https://watch.whatevertinfoil.de"
+      "https://watch.whatevertinfoil.de",
+      "https://piped.qdi.fi"
     ],
     "tor": [],
     "i2p": [],
@@ -68,7 +67,7 @@
   },
   "pipedMaterial": {
     "clearnet": [
-      "https://piped-material.১.net",
+      "https://piped-material.xn--17b.net",
       "https://piped-material.ftp.sh"
     ],
     "tor": [],
@@ -77,12 +76,9 @@
   },
   "cloudtube": {
     "clearnet": [
-      "https://tube.cadence.moe",
-      "https://yt.beparanoid.de"
-    ],
-    "tor": [
-      "http://yt.prnoid54e44a4bduq5due64jkk7wcnkxcp5kv3juncm7veptjcqudgyd.onion"
+      "https://tube.cadence.moe"
     ],
+    "tor": [],
     "i2p": [],
     "loki": []
   },
@@ -92,7 +88,6 @@
       "https://proxitok.pussthecat.org",
       "https://tok.habedieeh.re",
       "https://proxitok.esmailelbob.xyz",
-      "https://cringe.whatever.social",
       "https://proxitok.dhusch.de",
       "https://proxitok.privacydev.net",
       "https://proxitok.odyssey346.dev",
@@ -100,7 +95,9 @@
       "https://tok.adminforge.de",
       "https://proxitok.manasiwibi.com"
     ],
-    "tor": [],
+    "tor": [
+      "http://vywqfflneajejuhg7o5iklqvzemu2fcdrb3gtkvnyqsho6qin5svdsad.onion"
+    ],
     "i2p": [],
     "loki": []
   },
@@ -131,7 +128,7 @@
   "nitter": {
     "clearnet": [
       "https://nitter.net",
-      "https://nitter.42l.fr",
+      "https://nitter.lacontrevoie.fr",
       "https://nitter.pussthecat.org",
       "https://nitter:nitter@nitter.nixnet.services",
       "https://nitter.fdn.fr",
@@ -206,7 +203,12 @@
       "https://nitter.manasiwibi.com",
       "https://nitter.smnz.de",
       "https://nitter.twei.space",
-      "https://nitter.inpt.fr"
+      "https://nitter.inpt.fr",
+      "https://nitter.d420.de",
+      "https://nitter.caioalonso.com",
+      "https://nitter.at",
+      "https://nitter.drivet.xyz",
+      "https://nitter.pw"
     ],
     "tor": [
       "http://nitter7bryz3jv7e3uekphigvmoyoem4al3fynerxkj22dmoxoq553qd.onion",
@@ -232,6 +234,7 @@
       "http://wiio4sgs4247brk7hj6qck2jxnvldwfdbguigc5ivpxrsegnliyfvuqd.onion",
       "http://qwikxx2erhx6qrymued6ox2qkf2yeogjwypqvzoif4fqkljixasr6oid.onion",
       "http://4g47cxugkohbweao2x66nnxxfoe3k7gdfzxej537nhdbwr522sbjxeqd.onion",
+      "http://nt.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion",
       "http://tw.lpoaj7z2zkajuhgnlltpeqh3zyq7wk2iyeggqaduhgxhyajtdt2j7wad.onion"
     ],
     "i2p": [
@@ -458,21 +461,27 @@
       "http://quetre.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion",
       "http://qr.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion"
     ],
-    "i2p": [],
+    "i2p": [
+      "http://vernnflenvsqccuanaun7yydnmturi4jkyxlyzhn6ultpje66c3q.b32.i2p"
+    ],
     "loki": []
   },
   "libremdb": {
     "clearnet": [
-      "https://libremdb.herokuapp.com",
+      "https://libremdb.iket.me",
       "https://libremdb.pussthecat.org",
       "https://libremdbeu.herokuapp.com",
       "https://lmdb.tokhmi.xyz",
-      "https://libremdb.esmailelbob.xyz"
+      "https://libremdb.esmailelbob.xyz",
+      "https://ld.vern.cc"
     ],
     "tor": [
-      "http://libremdb.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd.onion"
+      "http://libremdb.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion",
+      "http://ld.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion"
+    ],
+    "i2p": [
+      "http://vernz3ubrntql4wrgyrssd6u3qzi36zrhz2agbo6vibzbs5olk2q.b32.i2p"
     ],
-    "i2p": [],
     "loki": []
   },
   "simplyTranslate": {
@@ -529,6 +538,7 @@
   "searx": {
     "clearnet": [
       "https://dynabyte.ca",
+      "https://icanfindit.online",
       "https://jsearch.pw",
       "https://search.ethibox.fr",
       "https://search.snopyta.org",
@@ -562,16 +572,17 @@
       "https://suche.uferwerk.org",
       "https://sx.catgirl.cloud",
       "https://timdor.noip.me/searx",
+      "https://xo.wtf",
       "https://searx.roflcopter.fr"
     ],
     "tor": [
       "http://3afisqjw2rxm6z7mmstyt5rx75qfqrgxnkzftknbp2vhipr2nrmrjdyd.onion",
-      "http://4n53nafyi77iplnbrpmxnp3x4exbswwxigujaxy3b37fvr7bvlopxeyd.onion",
+      "http://w5rl6wsd7mzj4bdkbuqvzidet5osdsm5jhg2f7nvfidakfq5exda5wid.onion",
       "http://yra4tke2pwcnatxjkufpw6kvebu3h3ti2jca2lcdpgx3mpwol326lzid.onion",
       "http://z5vawdol25vrmorm4yydmohsd4u6rdoj2sylvoi3e3nqvxkvpqul7bqd.onion",
       "http://zbuc3bbzbfdqqo2x46repx2ddajbha6fpsjeeptjhhhhzji3zopxdqyd.onion",
       "http://f4qfqajszpx5b7itzxt6mb7kj4ktpgbdq7lq6xaiqyqx6a7de3epptad.onion",
-      "http://searxfilowxokbogygrigir4wqxfxqzuxofxgdon7dg6rsii4yxzytyd.onion"
+      "http://searx.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion"
     ],
     "i2p": [
       "http://ransack.i2p",
@@ -584,7 +595,6 @@
       "https://darmarit.org/searx",
       "https://de.xcxc.ml",
       "https://etsi.me",
-      "https://icanfindit.online",
       "https://jackgoss.xyz",
       "https://metasearch.nl",
       "https://northboot.xyz",
@@ -594,6 +604,7 @@
       "https://priv.au",
       "https://privatus.live",
       "https://s.frlt.one",
+      "https://s.trung.fun",
       "https://s.zhaocloud.net",
       "https://saber.tk",
       "https://search.0relay.com",
@@ -645,7 +656,8 @@
       "https://searx.slipfox.xyz/searx",
       "https://searx.tiekoetter.com",
       "https://searx.zcyph.cc",
-      "https://searxng.nicfab.it",
+      "https://searxng.dupa.edu.pl",
+      "https://searxng.nicfab.eu",
       "https://searxng.zackptg5.com",
       "https://serx.ml",
       "https://sh0.it",
@@ -655,10 +667,10 @@
       "https://trydex.tk/searxng",
       "https://www.gruble.de",
       "https://www.webrats.xyz",
-      "https://xo.wtf"
+      "https://xcxc.ml"
     ],
     "tor": [
-      "http://w5rl6wsd7mzj4bdkbuqvzidet5osdsm5jhg2f7nvfidakfq5exda5wid.onion",
+      "http://4n53nafyi77iplnbrpmxnp3x4exbswwxigujaxy3b37fvr7bvlopxeyd.onion",
       "http://privateoz3u5utrimal2edr56j3r5caakektxxgixigdkycuxigvquid.onion",
       "http://b6sxmon57qza6dt36li7huabie5ntrvjr4q5rc2vvbn4hqvzd4phrvyd.onion",
       "http://searxngg6zleq6ceboe5ltkyo4hyrb3aaycrgzmrljv3jjlb5vcytead.onion",
@@ -666,7 +678,7 @@
       "http://b2c7fvbhnfvwnl6oh2tydhzfx4i37kmmrycq42heqbbe7wovq3uzenid.onion",
       "http://searxdr3pqz4nydgnqocsia2xbywptxbkympa2emn7zlgggrir4bkfad.onion",
       "http://searx.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion",
-      "http://searx.micohauwkjbyw5meacrb4ipicwvwg4xtzl7y7viv53kig2mdcsvwkyyd.onion",
+      "http://searxfilowxokbogygrigir4wqxfxqzuxofxgdon7dg6rsii4yxzytyd.onion",
       "http://searx.privpw3tndpkw6pnp3g727zfgfdzbu3k6a7chv226s3xymv2p4eiuqyd.onion",
       "http://rq2w52kyrif3xpfihkgjnhqm3a5aqhoikpv72z3drpjglfzc2wr5z4yd.onion",
       "http://fub6vgedgeadlu3ctskrpkcqjruh76tckwtj5swfhyblgml2tzgzckqd.onion/searx",
@@ -698,23 +710,9 @@
     "loki": []
   },
   "librex": {
-    "clearnet": [
-      "https://librex.beparanoid.de",
-      "https://librex.extravi.dev",
-      "https://search.davidovski.xyz",
-      "https://search.funami.tech",
-      "https://librex.catalyst.sx",
-      "https://search.madreyk.xyz",
-      "https://search.pabloferreiro.es"
-    ],
-    "tor": [
-      "http://librex.2356uhnbpv5nk3bni5bv6jg2cd6lgj664kwx3lhyelstpttpyv4kk2qd.onion",
-      "http://ncblhz7q4sfbf755bdbhebfzxcpypz7ewafgi4agatecojz7pln4i3id.onion",
-      "http://librex.so2mpiyfo4cje7bof5v52y3cvjyo2haxpqfvut4sr6gj2ul4mddx2jid.onion"
-    ],
-    "i2p": [
-      "http://rra33hiaf6nmby7jfpqe2gqmng3jnzkvbu2n7jgce7vbhoyuhzya.b32.i2p"
-    ],
+    "clearnet": [],
+    "tor": [],
+    "i2p": [],
     "loki": []
   },
   "rimgo": {
@@ -814,6 +812,16 @@
     "loki": []
   },
   "peertube": [
+    "https://search.joinpeertube.org",
+    "https://tbh.co-shaoghal.net",
+    "https://tube.kansanvalta.org",
+    "https://duanrra.cf",
+    "https://ytube.retronerd.at",
+    "https://tube.media-techport.de",
+    "https://notobono.de",
+    "https://video.vegafjord.me",
+    "https://peertube-us.howlround.com",
+    "https://peertube-eu.howlround.com",
     "https://pt.freedomwolf.cc",
     "https://vr360tube.online",
     "https://bodavr.com",
@@ -870,8 +878,6 @@
     "https://video.3cmr.fr",
     "https://peertube.miguelcr.me",
     "https://video.thinkof.name",
-    "https://nekofans.tv",
-    "https://video.comun.al",
     "https://video.occm.cc",
     "https://tube-action-educative.apps.education.fr",
     "https://jahve.pl",
@@ -888,7 +894,6 @@
     "https://tube-education-physique-et-sportive.apps.education.fr",
     "https://videos.lemouvementassociatif-pdl.org",
     "https://playroom.kitsunes.world",
-    "https://tube2.nous.media",
     "https://peertube.0x5e.eu",
     "https://tube.darknight-coffee.org",
     "https://play.mittdata.se",
@@ -947,13 +952,11 @@
     "https://videos.tormentasolar.win",
     "https://tube.nestor.coop",
     "https://live.oldskool.fi",
-    "https://dytube.com",
     "https://tube.thierrytalbert.fr",
     "https://peertube.informaction.info",
     "https://tube.ac-amiens.fr",
     "https://tube.alado.space",
     "https://tube.network.europa.eu",
-    "https://vnchich.com",
     "https://pt.maciej.website",
     "https://peertube.frontmediatique.fr",
     "https://peertube.bgzashtita.es",
@@ -967,7 +970,6 @@
     "https://videos.grafo.zone",
     "https://tube.chocoflan.net",
     "https://video.pthreat.co",
-    "https://peertube.egroc.de",
     "https://pt.k2s.sk",
     "https://video.cats-home.net",
     "https://peertube.narrativerry.xyz",
@@ -986,10 +988,8 @@
     "https://pierre.tube",
     "https://mirametube.fr",
     "https://vidz.dou.bet",
-    "https://videos.redeyes.site",
     "https://video.hostpath.de",
     "https://free-streams.com",
-    "https://tube.pawelko.net",
     "https://video.livecchi.cloud",
     "https://peertube.gsugambit.com",
     "https://pt.nospy.net",
@@ -1008,7 +1008,6 @@
     "https://yt.x1337x.fr",
     "https://videos.rabbit-company.com",
     "https://video.paradigmthreat.net",
-    "https://video.lincolncyber.com",
     "https://vid.twhtv.club",
     "https://video.retroedge.tech",
     "https://truvitv.com",
@@ -1025,7 +1024,6 @@
     "https://video.mttv.it",
     "https://peertube.cloud.nerdraum.de",
     "https://vid.pretok.tv",
-    "https://videos.slownewsdayshow.com",
     "https://videos.sarcasmstardust.com",
     "https://videos.factsonthegroundshow.com",
     "https://tv.santic-zombie.ru",
@@ -1034,8 +1032,6 @@
     "https://video.snug.moe",
     "https://video.avant-le-strike.buzz",
     "https://videos.ritimo.org",
-    "https://videos.ephphatha.church",
-    "https://video.cerclearistote.com",
     "https://video.greenmycity.eu",
     "https://przej.me",
     "https://pt.mezzo.moe",
@@ -1047,13 +1043,11 @@
     "https://bee-tube.fr",
     "https://vid.prometheus.systems",
     "https://tube.nx12.net",
-    "https://redundant2.peertube.support",
     "https://peertube.ignifi.me",
     "https://tv.based.quest",
     "https://peertube.beardedtek.com",
     "https://creemoseducacioninclusiva.uma.es",
     "https://videos.yeswiki.net",
-    "https://peertube.autogestioncitoyenne.org",
     "https://video.r3s.nrw",
     "https://peertube.semweb.pro",
     "https://poast.tv",
@@ -1067,14 +1061,12 @@
     "https://peertube.chatinbit.com",
     "https://peertube.ffs2play.fr",
     "https://peertube.swarm.solvingmaz.es",
-    "https://film.node9.org",
     "https://peertube.mi-site.net",
     "https://raptube.antipub.org",
     "https://video.cm-en-transition.fr",
     "https://tube.koweb.fr",
     "https://peertube.genma.fr",
     "https://tv.generallyrubbish.net.au",
-    "https://videos.codingotaku.com",
     "https://foss.tube",
     "https://peertube.satoshishop.de",
     "https://ua.peertube.red",
@@ -1102,7 +1094,6 @@
     "https://polskijutub.mkljczk.pl",
     "https://peertube.noussommes.org",
     "https://exode.me",
-    "https://megatube.lilomoino.fr",
     "https://video.anartist.org",
     "https://peertube.home.x0r.fr",
     "https://peertube.marud.fr",
@@ -1155,7 +1146,6 @@
     "https://www.orion-hub.fr",
     "https://tv.orion-serv.fr",
     "https://video.interru.io",
-    "https://tube.cnr.it",
     "https://peertube.dtmf.ca",
     "https://tube.ponsonaille.fr",
     "https://tube.int5.net",
@@ -1173,12 +1163,9 @@
     "https://video.antopie.org",
     "https://vtr.chikichiki.tube",
     "https://fedimovie.com",
-    "https://videos.thinkerview.com",
     "https://tube.doctors4covidethics.org",
-    "https://yoba.tv",
     "https://tube.mediainformationcenter.de",
     "https://peertube.communecter.org",
-    "https://peertube.librosphere.fr",
     "https://queermotion.org",
     "https://video.audiovisuel-participatif.org",
     "https://peertube.vip",
@@ -1309,7 +1296,6 @@
     "https://peertube.alpharius.io",
     "https://ptb.lunarviews.net",
     "https://ovaltube.codinglab.ch",
-    "https://video.wilkie.how",
     "https://videos.ahp-numerique.fr",
     "https://auf1.eu",
     "https://tube.toontoet.nl",
@@ -1439,7 +1425,6 @@
     "https://videos.john-livingston.fr",
     "https://melsungen.peertube-host.de",
     "https://evangelisch.video",
-    "https://tube.anufrij.de",
     "https://videos.mastodont.cat",
     "https://media.undeadnetwork.de",
     "https://tube.dragonpsi.xyz",
@@ -1463,7 +1448,6 @@
     "https://video.ecole-89.com",
     "https://tube.kai-stuht.com",
     "https://video.fbxl.net",
-    "https://live.libratoi.org",
     "https://video.p1ng0ut.social",
     "https://watch.deranalyst.ch",
     "https://video.discord-insoumis.fr",
@@ -1492,7 +1476,6 @@
     "https://kodcast.com",
     "https://video.altertek.org",
     "https://ruraletv.ovh",
-    "https://videos.weblib.re",
     "https://tube.oisux.org",
     "https://peertube.louisematic.site",
     "https://clap.nerv-project.eu",
@@ -1510,7 +1493,6 @@
     "https://fotogramas.politicaconciencia.org",
     "https://peertube.pl",
     "https://peertube.manalejandro.com",
-    "https://www4.mir.inter21.net",
     "https://video.csc49.fr",
     "https://tube.wolfe.casa",
     "https://video.dresden.network",
@@ -1534,14 +1516,12 @@
     "https://tube.nox-rhea.org",
     "https://peertube.securitymadein.lu",
     "https://tube.rita.moe",
-    "https://tuktube.com",
     "https://mytube.kn-cloud.de",
     "https://tube.nuagelibre.fr",
     "https://video.nogafam.es",
     "https://peertube.stream",
     "https://videos.leslionsfloorball.fr",
     "https://player.ojamajo.moe",
-    "https://ftsi.ru",
     "https://video.cigliola.com",
     "https://xxx.noho.st",
     "https://peertube.stefofficiel.me",
@@ -1635,7 +1615,6 @@
     "https://peertube.debian.social",
     "https://tube.piweb.be",
     "https://peertube.su",
-    "https://video.hackers.town",
     "https://tube.fdn.fr",
     "https://peertube.demonix.fr",
     "https://videos.hauspie.fr",
@@ -1773,4 +1752,4 @@
     "https://peertube2.cpy.re",
     "https://peertube.cpy.re"
   ]
-}
+}
\ No newline at end of file
diff --git a/src/instances/get_instances.py b/src/instances/get_instances.py
index c789f551..96902feb 100644
--- a/src/instances/get_instances.py
+++ b/src/instances/get_instances.py
@@ -137,7 +137,7 @@ def fetchFromFile(frontend, name):
     print(Fore.GREEN + 'Fetched ' + Style.RESET_ALL + name)
 
 
-def fetchJsonList(frontend, name, url, urlItem):
+def fetchJsonList(frontend, name, url, urlItem, jsonObject):
     try:
         r = requests.get(url)
         rJson = json.loads(r.text)
@@ -152,8 +152,8 @@ def fetchJsonList(frontend, name, url, urlItem):
                             if item[urlItem[network]].strip() != '':
                                 _list[network].append(item[urlItem[network]])
         else:
-            if frontend == 'librarian':
-                rJson = rJson['instances']  # I got lazy :p   Might fix this at some point...
+            if jsonObject:
+                rJson = rJson['instances']
             for item in rJson:
                 tmpItem = item
                 if urlItem is not None:
@@ -313,15 +313,15 @@ def libreddit():
 
 
 def teddit():
-    fetchJsonList('teddit', 'Teddit', 'https://codeberg.org/teddit/teddit/raw/branch/main/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None})
+    fetchJsonList('teddit', 'Teddit', 'https://codeberg.org/teddit/teddit/raw/branch/main/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None}, False)
 
 
 def wikiless():
-    fetchJsonList('wikiless', 'Wikiless', 'https://wikiless.org/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None})
+    fetchJsonList('wikiless', 'Wikiless', 'https://wikiless.org/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None}, False)
 
 
 def scribe():
-    fetchJsonList('scribe', 'Scribe', 'https://git.sr.ht/~edwardloveall/scribe/blob/main/docs/instances.json', None)
+    fetchJsonList('scribe', 'Scribe', 'https://git.sr.ht/~edwardloveall/scribe/blob/main/docs/instances.json', None, False)
 
 
 def quetre():
@@ -363,7 +363,7 @@ def simplytranslate():
 
 
 def linvgatranslate():
-    fetchJsonList('lingva', 'LingvaTranslate', 'https://raw.githubusercontent.com/TheDavidDelta/lingva-translate/main/instances.json', None)
+    fetchJsonList('lingva', 'LingvaTranslate', 'https://raw.githubusercontent.com/TheDavidDelta/lingva-translate/main/instances.json', None, False)
 
 
 def searx_searxng():
@@ -406,15 +406,15 @@ def whoogle():
 
 
 def librex():
-    fetchRegexList('librex', 'LibreX', 'https://raw.githubusercontent.com/hnhx/librex/main/README.md', r"\| {1,2}\[(?:(?:[a-zA-Z0-9]+\.)+[a-zA-Z]{2,}|✅)\]\((https?:\/{2}(?:[a-zA-Z0-9]+\.)+[a-zA-Z0-9]{2,})")
+    fetchJsonList('librex', 'LibreX', 'https://raw.githubusercontent.com/hnhx/librex/main/instances.json', {'clearnet': 'clearnet', 'tor': 'tor', 'i2p': 'i2p', 'loki': None}, True)
 
 
 def rimgo():
-    fetchJsonList('rimgo', 'rimgo', 'https://codeberg.org/video-prize-ranch/rimgo/raw/branch/main/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None})
+    fetchJsonList('rimgo', 'rimgo', 'https://codeberg.org/video-prize-ranch/rimgo/raw/branch/main/instances.json', {'clearnet': 'url', 'tor': 'onion', 'i2p': 'i2p', 'loki': None}, False)
 
 
 def librarian():
-    fetchJsonList('librarian', 'Librarian', 'https://codeberg.org/librarian/librarian/raw/branch/main/instances.json', 'url')
+    fetchJsonList('librarian', 'Librarian', 'https://codeberg.org/librarian/librarian/raw/branch/main/instances.json', 'url', True)
 
 
 def neuters():
@@ -426,7 +426,7 @@ def beatbump():
 
 
 def hyperpipe():
-    fetchJsonList('hyperpipe', 'Hyperpipe', 'https://codeberg.org/Hyperpipe/pages/raw/branch/main/api/frontend.json', 'url')
+    fetchJsonList('hyperpipe', 'Hyperpipe', 'https://codeberg.org/Hyperpipe/pages/raw/branch/main/api/frontend.json', 'url', False)
 
 
 def facil():
@@ -498,7 +498,7 @@ for k1, v1 in mightyList.items():
                         cloudflare.append(instance)
                     if not instance.endswith('.onion') and not instance.endswith('.i2p') and not instance.endswith('.loki') and is_authenticate(instance):
                         authenticate.append(instance)
-                    if not instance.endswith('.onion') and not instance.endswith('.i2p') and not instance.endswith('.loki') and is_offline(instance):
+                    elif not instance.endswith('.onion') and not instance.endswith('.i2p') and not instance.endswith('.loki') and is_offline(instance):
                         offline.append(instance)
 
 peertube()
diff --git a/src/pages/background/background.js b/src/pages/background/background.js
index eba436cb..7186144b 100644
--- a/src/pages/background/background.js
+++ b/src/pages/background/background.js
@@ -1,3 +1,250 @@
+<<<<<<< HEAD
+"use strict"
+
+import generalHelper from "../../assets/javascripts/general.js"
+import utils from "../../assets/javascripts/utils.js"
+
+import youtubeHelper from "../../assets/javascripts/youtube/youtube.js"
+import youtubeMusicHelper from "../../assets/javascripts/youtubeMusic.js"
+import twitterHelper from "../../assets/javascripts/twitter.js"
+import instagramHelper from "../../assets/javascripts/instagram.js"
+import redditHelper from "../../assets/javascripts/reddit.js"
+import searchHelper from "../../assets/javascripts/search.js"
+import translateHelper from "../../assets/javascripts/translate/translate.js"
+import mapsHelper from "../../assets/javascripts/maps.js"
+import wikipediaHelper from "../../assets/javascripts/wikipedia.js"
+import mediumHelper from "../../assets/javascripts/medium.js"
+import quoraHelper from "../../assets/javascripts/quora.js"
+import libremdbHelper from "../../assets/javascripts/imdb.js"
+import reutersHelper from "../../assets/javascripts/reuters.js"
+import imgurHelper from "../../assets/javascripts/imgur.js"
+import tiktokHelper from "../../assets/javascripts/tiktok.js"
+import sendTargetsHelper from "../../assets/javascripts/sendTargets.js"
+import peertubeHelper from "../../assets/javascripts/peertube.js"
+import lbryHelper from "../../assets/javascripts/lbry.js"
+
+import frontend from "../../assets/javascripts/frontend.js"
+
+window.browser = window.browser || window.chrome
+
+browser.runtime.onInstalled.addListener(details => {
+	function initDefaults() {
+		fetch("/instances/blacklist.json")
+			.then(response => response.text())
+			.then(async data => {
+				browser.storage.local.clear(() => {
+					browser.storage.local.set({ cloudflareBlackList: JSON.parse(data).cloudflare }, () => {
+						browser.storage.local.set({ authenticateBlackList: JSON.parse(data).authenticate }, () => {
+							browser.storage.local.set({ offlineBlackList: JSON.parse(data).offline }, () => {
+								generalHelper.initDefaults()
+								youtubeHelper.initDefaults()
+								youtubeMusicHelper.initDefaults()
+								twitterHelper.initDefaults()
+								instagramHelper.initDefaults()
+								mapsHelper.initDefaults()
+								searchHelper.initDefaults()
+								translateHelper.initDefaults()
+								mediumHelper.initDefaults()
+								quoraHelper.initDefaults()
+								libremdbHelper.initDefaults()
+								reutersHelper.initDefaults()
+								redditHelper.initDefaults()
+								wikipediaHelper.initDefaults()
+								imgurHelper.initDefaults()
+								tiktokHelper.initDefaults()
+								sendTargetsHelper.initDefaults()
+								peertubeHelper.initDefaults()
+								lbryHelper.initDefaults()
+							})
+						})
+					})
+				})
+			})
+	}
+	if (details.reason == "install") initDefaults()
+
+	// if (details.reason == 'install' || (details.reason == "update" && details.previousVersion != browser.runtime.getManifest().version)) {
+	//   if (details.reason == "update")
+	//     browser.storage.local.get(null, r => {
+	//       if (r.theme) {
+	//         const old = encodeURIComponent(JSON.stringify(r))
+	//         browser.tabs.create({ url: browser.runtime.getURL(`/pages/background/reset_warning.html?data=${old}`) });
+	//       }
+	//       initDefaults();
+	//     })
+	//   else initDefaults();
+	// }
+})
+
+let BYPASSTABs = []
+browser.webRequest.onBeforeRequest.addListener(
+	details => {
+		const url = new URL(details.url)
+		if (new RegExp(/^chrome-extension:\/{2}.*\/instances\/.*.json$/).test(url.href) && details.type == "xmlhttprequest") return
+		let initiator
+		try {
+			if (details.originUrl) initiator = new URL(details.originUrl)
+			else if (details.initiator) initiator = new URL(details.initiator)
+		} catch {
+			return null
+		}
+
+		let newUrl = youtubeMusicHelper.redirect(url, details.type)
+		if (!newUrl) newUrl = youtubeHelper.redirect(url, details.type, details.tabId, initiator)
+		if (!newUrl) newUrl = twitterHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = instagramHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = mapsHelper.redirect(url, initiator)
+		if (!newUrl) newUrl = redditHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = mediumHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = quoraHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = libremdbHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = reutersHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = imgurHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = tiktokHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = sendTargetsHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = peertubeHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = lbryHelper.redirect(url, details.type, initiator)
+		if (!newUrl) newUrl = translateHelper.redirect(url)
+		if (!newUrl) newUrl = searchHelper.redirect(url)
+		if (!newUrl) newUrl = wikipediaHelper.redirect(url)
+
+		if (details.frameAncestors && details.frameAncestors.length > 0 && generalHelper.isException(new URL(details.frameAncestors[0].url))) newUrl = null
+
+		if (generalHelper.isException(url)) newUrl = "BYPASSTAB"
+		if (BYPASSTABs.includes(details.tabId)) newUrl = null
+
+		if (newUrl) {
+			if (newUrl === "CANCEL") {
+				console.log(`Canceled ${url}`)
+				return { cancel: true }
+			}
+			if (newUrl === "BYPASSTAB") {
+				console.log(`Bypassed ${details.tabId} ${url}`)
+				if (!BYPASSTABs.includes(details.tabId)) BYPASSTABs.push(details.tabId)
+				return null
+			}
+			console.info("Redirecting", url.href, "=>", newUrl)
+			return { redirectUrl: newUrl }
+		}
+		return null
+	},
+	{ urls: ["<all_urls>"] },
+	["blocking"]
+)
+
+browser.tabs.onRemoved.addListener(tabId => {
+	const i = BYPASSTABs.indexOf(tabId)
+	if (i > -1) {
+		BYPASSTABs.splice(i, 1)
+		console.log("Removed BYPASSTABs", tabId)
+	}
+})
+
+browser.webRequest.onHeadersReceived.addListener(
+	e => {
+		let response = youtubeHelper.removeXFrameOptions(e)
+		if (!response) response = twitterHelper.removeXFrameOptions(e)
+		return response
+	},
+	{ urls: ["<all_urls>"] },
+	["blocking", "responseHeaders"]
+)
+
+async function redirectOfflineInstance(url, tabId) {
+	let newUrl = await youtubeHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await twitterHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await instagramHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await redditHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await searchHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await translateHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await mediumHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await quoraHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await libremdbHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await tiktokHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await imgurHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await wikipediaHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await peertubeHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await lbryHelper.switchInstance(url, true)
+	if (!newUrl) newUrl = await youtubeMusicHelper.switchInstance(url, true)
+
+	if (newUrl) {
+		if (counter >= 5) {
+			browser.tabs.update(tabId, {
+				url: `/pages/errors/instance_offline.html?url=${encodeURIComponent(newUrl)}`,
+			})
+			counter = 0
+		} else {
+			browser.tabs.update(tabId, { url: newUrl })
+			counter++
+		}
+	}
+}
+let counter = 0
+
+function isAutoRedirect() {
+	return new Promise(resolve => browser.storage.local.get("autoRedirect", r => resolve(r.autoRedirect == true)))
+}
+
+browser.webRequest.onResponseStarted.addListener(
+	async details => {
+		if (!(await isAutoRedirect())) return null
+		if (details.type == "main_frame" && details.statusCode >= 500) redirectOfflineInstance(new URL(details.url), details.tabId)
+	},
+	{ urls: ["<all_urls>"] }
+)
+
+browser.webRequest.onErrorOccurred.addListener(
+	async details => {
+		if (!(await isAutoRedirect())) return
+		if (details.type == "main_frame") redirectOfflineInstance(new URL(details.url), details.tabId)
+	},
+	{ urls: ["<all_urls>"] }
+)
+
+browser.commands.onCommand.addListener(command => {
+	if (command === "switchInstance") utils.switchInstance()
+	else if (command == "copyRaw") utils.copyRaw()
+	else if (command == "unify") utils.unify()
+})
+
+browser.contextMenus.create({
+	id: "settings",
+	title: browser.i18n.getMessage("Settings"),
+	contexts: ["browser_action"],
+})
+
+browser.contextMenus.create({
+	id: "switchInstance",
+	title: browser.i18n.getMessage("switchInstance"),
+	contexts: ["browser_action"],
+})
+
+browser.contextMenus.create({
+	id: "copyRaw",
+	title: browser.i18n.getMessage("copyRaw"),
+	contexts: ["browser_action"],
+})
+
+browser.contextMenus.create({
+	id: "unify",
+	title: browser.i18n.getMessage("unifySettings"),
+	contexts: ["browser_action"],
+})
+
+browser.contextMenus.onClicked.addListener(info => {
+	if (info.menuItemId == "switchInstance") utils.switchInstance()
+	else if (info.menuItemId == "settings") browser.runtime.openOptionsPage()
+	else if (info.menuItemId == "copyRaw") utils.copyRaw()
+	else if (info.menuItemId == "unify") utils.unify()
+})
+
+browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
+	if (message.function === "unify") utils.unify(false).then(r => sendResponse({ response: r }))
+	return true
+})
+
+browser.storage.local.set({ version: browser.runtime.getManifest().version })
+=======
 "use strict"

 

 import generalHelper from "../../assets/javascripts/general.js"

@@ -189,3 +436,4 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
 	if (message.function === "unify") utils.unify(false).then(r => sendResponse({ response: r }))

 	return true

 })

+>>>>>>> optimizations
diff --git a/src/pages/errors/instance_offline.html b/src/pages/errors/instance_offline.html
index 4f27445c..a74caec2 100644
--- a/src/pages/errors/instance_offline.html
+++ b/src/pages/errors/instance_offline.html
@@ -27,8 +27,9 @@
 
 	<body>
 		<div>
-			<p id="message" data-localise="__MSG_instanceOffline__">
-				This instance is offline, you'll be redirected after&nbsp;<span id="number">2</span>&nbsp;<x data-localise="__MSG_sec__">seconds</x>
+			<p id="message">
+				<span data-localise="__MSG_instanceOffline__">This instance is offline, you'll be redirected after</span>
+				<span id="number">2</span> <x data-localise="__MSG_sec__">seconds</x>
 			</p>
 			<button id="cancel" data-localise="__MSG_cancel__">Cancel</button>
 		</div>
diff --git a/src/pages/options/widgets/general.js b/src/pages/options/widgets/general.js
index a58ca3e6..cba46de2 100644
--- a/src/pages/options/widgets/general.js
+++ b/src/pages/options/widgets/general.js
@@ -56,11 +56,12 @@ function exportSettings() {
 		let resultString = JSON.stringify(result.options, null, "  ")
 		exportSettingsElement.href = "data:application/json;base64," + btoa(resultString)
 		exportSettingsElement.download = "libredirect-settings.json"
+		return
 	})
 }
 exportSettings()
 
-document.getElementById("general_page").addEventListener("click", exportSettings)
+document.getElementById("general_page").onclick = exportSettings
 
 let importSettingsElement = document.getElementById("import-settings")
 let importSettingsElementText = document.getElementById("import_settings_text")