window.browser = window.browser || window.chrome /** * @param {Array.} instances * @returns {T} */ function getRandomInstance(instances) { return instances[~~(instances.length * Math.random())] } /** * @param {string} currentInstanceUrl * @param {Array.} 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.} frontends * @prop {Object} options */ /** * @typedef {Object} Config * @prop {Object.} services */ /** * @returns {Promise} */ 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>} */ 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, }