227 lines
4.6 KiB
JavaScript
227 lines
4.6 KiB
JavaScript
window.browser = window.browser || window.chrome
|
|
|
|
/**
|
|
* @param {Array.<T>} instances
|
|
* @returns {T}
|
|
*/
|
|
function getRandomInstance(instances) {
|
|
return instances[~~(instances.length * Math.random())]
|
|
}
|
|
|
|
/**
|
|
* @param {string} currentInstanceUrl
|
|
* @param {Array.<T>} instances
|
|
* @returns {T}
|
|
*/
|
|
function getNextInstance(currentInstanceUrl, instances) {
|
|
const currentInstanceIndex = instances.indexOf(currentInstanceUrl);
|
|
|
|
if (currentInstanceIndex === -1){
|
|
return getRandomInstance(instances);
|
|
}
|
|
|
|
const nextInstanceIndex = (currentInstanceIndex + 1) % instances.length;
|
|
|
|
return instances[nextInstanceIndex];
|
|
}
|
|
|
|
/**
|
|
* @param {string} str
|
|
*/
|
|
function camelCase(str) {
|
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
}
|
|
|
|
/**
|
|
* @param {URL} url
|
|
*/
|
|
function protocolHost(url) {
|
|
if (url.username && url.password) return `${url.protocol}//${url.username}:${url.password}@${url.host}`
|
|
if (url.pathname == "/TekstoLibre/" && url.host.endsWith("github.io")) // workaround
|
|
return `${url.protocol}//${url.host}${url.pathname.slice(0, -1)}`
|
|
return `${url.protocol}//${url.host}`
|
|
}
|
|
|
|
/**
|
|
* @typedef FrontendInfo
|
|
* @prop {boolean} instanceList
|
|
* @prop {string} name
|
|
* @prop {string} url
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} Service
|
|
* @prop {Object.<string, FrontendInfo>} frontends
|
|
* @prop {Object} options
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} Config
|
|
* @prop {Object.<string, Service>} services
|
|
*/
|
|
|
|
/**
|
|
* @returns {Promise<Config>}
|
|
*/
|
|
function getConfig() {
|
|
return new Promise(resolve => {
|
|
fetch("/config.json")
|
|
.then(response => response.text())
|
|
.then(json => {
|
|
resolve(JSON.parse(json))
|
|
return
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @typedef {Object} Option
|
|
* @prop {string} frontend
|
|
*/
|
|
|
|
/**
|
|
* @returns {Promise<Object.<string, Option | string[]>>}
|
|
*/
|
|
function getOptions() {
|
|
return new Promise(resolve =>
|
|
browser.storage.local.get("options", r => {
|
|
resolve(r.options)
|
|
})
|
|
)
|
|
}
|
|
|
|
function getPingCache() {
|
|
return new Promise(resolve =>
|
|
browser.storage.local.get("pingCache", r => {
|
|
resolve(r.pingCache ?? {})
|
|
})
|
|
)
|
|
}
|
|
|
|
function getBlacklist(options) {
|
|
return new Promise(resolve => {
|
|
let url
|
|
if (options.fetchInstances == 'github') {
|
|
url = 'https://raw.githubusercontent.com/libredirect/instances/main/blacklist.json'
|
|
}
|
|
else if (options.fetchInstances == 'codeberg') {
|
|
url = 'https://codeberg.org/LibRedirect/instances/raw/branch/main/blacklist.json'
|
|
}
|
|
else {
|
|
resolve('disabled')
|
|
return
|
|
}
|
|
const http = new XMLHttpRequest()
|
|
http.open("GET", url, true)
|
|
http.onreadystatechange = () => {
|
|
if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) {
|
|
resolve(JSON.parse(http.responseText))
|
|
return
|
|
}
|
|
}
|
|
http.onerror = () => {
|
|
resolve()
|
|
return
|
|
}
|
|
http.ontimeout = () => {
|
|
resolve()
|
|
return
|
|
}
|
|
http.send(null)
|
|
})
|
|
}
|
|
|
|
function getList(options) {
|
|
return new Promise(resolve => {
|
|
let url
|
|
if (options.fetchInstances == 'github') {
|
|
url = 'https://raw.githubusercontent.com/libredirect/instances/main/data.json'
|
|
}
|
|
else if (options.fetchInstances == 'codeberg') {
|
|
url = 'https://codeberg.org/LibRedirect/instances/raw/branch/main/data.json'
|
|
}
|
|
else {
|
|
resolve('disabled')
|
|
return
|
|
}
|
|
const http = new XMLHttpRequest()
|
|
http.open("GET", url, true)
|
|
http.onreadystatechange = () => {
|
|
if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) {
|
|
resolve(JSON.parse(http.responseText))
|
|
return
|
|
}
|
|
}
|
|
http.onerror = () => {
|
|
resolve()
|
|
return
|
|
}
|
|
http.ontimeout = () => {
|
|
resolve()
|
|
return
|
|
}
|
|
http.send(null)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @param {string} href
|
|
*/
|
|
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)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @param {string} href
|
|
*/
|
|
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)
|
|
})
|
|
}
|
|
|
|
export default {
|
|
getRandomInstance,
|
|
getNextInstance,
|
|
protocolHost,
|
|
getList,
|
|
getBlacklist,
|
|
camelCase,
|
|
getConfig,
|
|
getOptions,
|
|
getPingCache,
|
|
ping,
|
|
}
|