Formatting wiht prettier

This commit is contained in:
ManeraKai 2024-07-21 21:22:09 +03:00
parent 8bf25954a3
commit cf8216da00
No known key found for this signature in database
GPG Key ID: 5ABC31FFD562E337
19 changed files with 3238 additions and 3270 deletions

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
src/_locales/
.github/
.gitea/

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"printWidth": 120,
"semi": false,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
}

View File

@ -11,34 +11,42 @@ A browser extension that redirects YouTube, Twitter, TikTok... requests to alter
</a> </a>
## Translate ## Translate
<a href="https://hosted.weblate.org/projects/libredirect/extension"> <a href="https://hosted.weblate.org/projects/libredirect/extension">
<img src ="./img/weblate.svg"> <img src ="./img/weblate.svg">
</a> </a>
## Development ## Development
Install [Node.js](https://nodejs.org/) Install [Node.js](https://nodejs.org/)
```bash ```bash
git clone https://github.com/libredirect/browser_extension git clone https://github.com/libredirect/browser_extension
cd browser_extension cd browser_extension
npm install npm install
npm run html # Generates html using Pug npm run html # Generates html using Pug
``` ```
#### Run on Firefox #### Run on Firefox
```bash ```bash
npm run start npm run start
``` ```
#### Build a zip package for Firefox #### Build a zip package for Firefox
```bash ```bash
npm run build npm run build
``` ```
#### Install the zip package on Firefox (temporarily) #### Install the zip package on Firefox (temporarily)
1. Type in the address bar: `about:debugging#/runtime/this-firefox` 1. Type in the address bar: `about:debugging#/runtime/this-firefox`
2. Press `Load Temporary Add-on...` 2. Press `Load Temporary Add-on...`
3. Select `libredirect-VERSION.zip` from `web-ext-artifacts` folder 3. Select `libredirect-VERSION.zip` from `web-ext-artifacts` folder
#### Install the zip package on Firefox ESR, Developer Edition, Nightly #### Install the zip package on Firefox ESR, Developer Edition, Nightly
1. Type in the address bar: `about:config` 1. Type in the address bar: `about:config`
2. Set `xpinstall.signatures.required` to `false` 2. Set `xpinstall.signatures.required` to `false`
3. Type in the address bar: `about:addons` 3. Type in the address bar: `about:addons`
@ -46,6 +54,7 @@ npm run build
5. Select `libredirect-VERSION.zip` from `web-ext-artifacts` folder 5. Select `libredirect-VERSION.zip` from `web-ext-artifacts` folder
#### Run on Chromium #### Run on Chromium
1. Open `chrome://extensions` 1. Open `chrome://extensions`
2. Enable `dev mode` 2. Enable `dev mode`
3. Select `load unpacked extension` 3. Select `load unpacked extension`

View File

@ -35,9 +35,9 @@ function all(service, frontend, options, config) {
*/ */
function regexArray(service, url, config, frontend) { function regexArray(service, url, config, frontend) {
let targetList = config.services[service].targets let targetList = config.services[service].targets
if (frontend && 'excludeTargets' in config.services[service].frontends[frontend]) { if (frontend && "excludeTargets" in config.services[service].frontends[frontend]) {
targetList = targetList.filter(val => targetList = targetList.filter(
!config.services[service].frontends[frontend].excludeTargets.includes(targetList.indexOf(val)) val => !config.services[service].frontends[frontend].excludeTargets.includes(targetList.indexOf(val))
) )
} }
for (const targetString in targetList) { for (const targetString in targetList) {
@ -67,7 +67,9 @@ async function redirectAsync(url, type, initiator, forceRedirection) {
function rewrite(url, frontend, randomInstance) { function rewrite(url, frontend, randomInstance) {
switch (frontend) { switch (frontend) {
case "hyperpipe": case "hyperpipe":
return `${randomInstance}${url.pathname}${url.search}`.replace(/\/search\?q=.*/, searchQuery => searchQuery.replace("?q=", "/")) return `${randomInstance}${url.pathname}${url.search}`.replace(/\/search\?q=.*/, searchQuery =>
searchQuery.replace("?q=", "/")
)
case "searx": case "searx":
case "searxng": case "searxng":
return `${randomInstance}/${url.search}` return `${randomInstance}/${url.search}`
@ -85,13 +87,13 @@ function rewrite(url, frontend, randomInstance) {
return url.href.replace(/^https?:\/{2}/, "yattee://") return url.href.replace(/^https?:\/{2}/, "yattee://")
case "freetube": case "freetube":
url.searchParams.delete("si") url.searchParams.delete("si")
return 'freetube://' + url.href return "freetube://" + url.href
case "freetubePwa": case "freetubePwa":
url.searchParams.delete("si") url.searchParams.delete("si")
return 'freetube://' + url.href return "freetube://" + url.href
case "poketube": { case "poketube": {
url.searchParams.delete("si") url.searchParams.delete("si")
if (url.pathname.startsWith('/channel')) { if (url.pathname.startsWith("/channel")) {
const reg = /\/channel\/(.*)\/?$/.exec(url.pathname) const reg = /\/channel\/(.*)\/?$/.exec(url.pathname)
if (reg) { if (reg) {
const id = reg[1] const id = reg[1]
@ -125,24 +127,28 @@ function rewrite(url, frontend, randomInstance) {
let [lat, lon, zoom] = [null, null, null] let [lat, lon, zoom] = [null, null, null]
const reg = url.pathname.match(/@(-?\d[0-9.]*),(-?\d[0-9.]*),(\d{1,2})[.z]/) const reg = url.pathname.match(/@(-?\d[0-9.]*),(-?\d[0-9.]*),(\d{1,2})[.z]/)
if (reg) { if (reg) {
[, lon, lat, zoom] = reg ;[, lon, lat, zoom] = reg
} else if (url.searchParams.has("center")) { } else if (url.searchParams.has("center")) {
// Set map centre if present // Set map centre if present
[lat, lon] = url.searchParams.get("center").split(",") ;[lat, lon] = url.searchParams.get("center").split(",")
zoom = url.searchParams.get("zoom") ?? "17" zoom = url.searchParams.get("zoom") ?? "17"
} }
return { zoom, lon, lat } return { zoom, lon, lat }
} }
function addressToLatLng(address) { function addressToLatLng(address) {
const http = new XMLHttpRequest() const http = new XMLHttpRequest()
http.open("GET", `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(address)}&format=json&limit=1`, false) http.open(
"GET",
`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(address)}&format=json&limit=1`,
false
)
http.send() http.send()
if (http.status == 200) { if (http.status == 200) {
const json = JSON.parse(http.responseText)[0] const json = JSON.parse(http.responseText)[0]
if (json) { if (json) {
return { return {
coordinate: `${json.lat},${json.lon}`, coordinate: `${json.lat},${json.lon}`,
boundingbox: `${json.boundingbox[2]},${json.boundingbox[1]},${json.boundingbox[3]},${json.boundingbox[0]}` boundingbox: `${json.boundingbox[2]},${json.boundingbox[1]},${json.boundingbox[3]},${json.boundingbox[0]}`,
} }
} }
return {} return {}
@ -164,9 +170,11 @@ function rewrite(url, frontend, randomInstance) {
let prefs = { layers: "mapnik" } let prefs = { layers: "mapnik" }
const mapCentreData = convertMapCentre(url) const mapCentreData = convertMapCentre(url)
if (mapCentreData.zoom && mapCentreData.lon && mapCentreData.lat) mapCentre = `#map=${mapCentreData.zoom}/${mapCentreData.lon}/${mapCentreData.lat}` if (mapCentreData.zoom && mapCentreData.lon && mapCentreData.lat)
mapCentre = `#map=${mapCentreData.zoom}/${mapCentreData.lon}/${mapCentreData.lat}`
if (url.pathname.includes("/embed")) { // https://www.google.com/maps/embed/v1/place?key=AIzaSyD4iE2xVSpkLLOXoyqT-RuPwURN3ddScAI&q=Eiffel+Tower,Paris+France if (url.pathname.includes("/embed")) {
// https://www.google.com/maps/embed/v1/place?key=AIzaSyD4iE2xVSpkLLOXoyqT-RuPwURN3ddScAI&q=Eiffel+Tower,Paris+France
const query = getQuery(url) const query = getQuery(url)
let { coordinate, boundingbox } = addressToLatLng(query) let { coordinate, boundingbox } = addressToLatLng(query)
prefs.bbox = boundingbox prefs.bbox = boundingbox
@ -184,26 +192,32 @@ function rewrite(url, frontend, randomInstance) {
} }
const regex1 = /\/dir\/([^@/]+)\/([^@/]+)\/@-?\d[0-9.]*,-?\d[0-9.]*,\d{1,2}[.z]/.exec(url.pathname) const regex1 = /\/dir\/([^@/]+)\/([^@/]+)\/@-?\d[0-9.]*,-?\d[0-9.]*,\d{1,2}[.z]/.exec(url.pathname)
const regex2 = /\/dir\/([^@/]+)\//.exec(url.pathname) const regex2 = /\/dir\/([^@/]+)\//.exec(url.pathname)
if (regex1) { // https://www.google.com/maps/dir/92+Rue+Moncey,+69003+Lyon,+France/M%C3%A9dip%C3%B4le+Lyon-Villeurbanne/@45.760254,4.8486298,13z?travelmode=bicycling if (regex1) {
const origin = addressToLatLng(decodeURIComponent(regex1[1])).coordinate ?? '' // https://www.google.com/maps/dir/92+Rue+Moncey,+69003+Lyon,+France/M%C3%A9dip%C3%B4le+Lyon-Villeurbanne/@45.760254,4.8486298,13z?travelmode=bicycling
const destination = addressToLatLng(decodeURIComponent(regex1[2])).coordinate ?? '' const origin = addressToLatLng(decodeURIComponent(regex1[1])).coordinate ?? ""
const destination = addressToLatLng(decodeURIComponent(regex1[2])).coordinate ?? ""
prefs.route = `${origin};${destination}` prefs.route = `${origin};${destination}`
} else if (regex2) { // https://www.google.com/maps/dir/92+Rue+Moncey,+69003+Lyon,+France/@45.760254,4.8486298,13z?travelmode=bicycling } else if (regex2) {
const origin = addressToLatLng(decodeURIComponent(regex2[1])).coordinate ?? '' // https://www.google.com/maps/dir/92+Rue+Moncey,+69003+Lyon,+France/@45.760254,4.8486298,13z?travelmode=bicycling
const origin = addressToLatLng(decodeURIComponent(regex2[1])).coordinate ?? ""
prefs.route = `${origin};` prefs.route = `${origin};`
} else { // https://www.google.com/maps/dir/?api=1&origin=Space+Needle+Seattle+WA&destination=Pike+Place+Market+Seattle+WA&travelmode=bicycling } else {
const origin = addressToLatLng(url.searchParams.get("origin")).coordinate ?? '' // https://www.google.com/maps/dir/?api=1&origin=Space+Needle+Seattle+WA&destination=Pike+Place+Market+Seattle+WA&travelmode=bicycling
const destination = addressToLatLng(url.searchParams.get("destination")).coordinate ?? '' const origin = addressToLatLng(url.searchParams.get("origin")).coordinate ?? ""
const destination = addressToLatLng(url.searchParams.get("destination")).coordinate ?? ""
prefs.route = `${origin};${destination}` prefs.route = `${origin};${destination}`
} }
return `${randomInstance}/directions?${prefsEncoded(prefs)}${mapCentre}` return `${randomInstance}/directions?${prefsEncoded(prefs)}${mapCentre}`
} else if (url.pathname.match(placeRegex)) { // https://www.google.com/maps/place/H%C3%B4tel+de+Londres+Eiffel/@40.9845265,28.7081268,14z } else if (url.pathname.match(placeRegex)) {
// https://www.google.com/maps/place/H%C3%B4tel+de+Londres+Eiffel/@40.9845265,28.7081268,14z
const query = url.pathname.match(placeRegex)[1] const query = url.pathname.match(placeRegex)[1]
return `${randomInstance}/search?query=${query}${mapCentre}` return `${randomInstance}/search?query=${query}${mapCentre}`
} else if (url.searchParams.has("ll")) { // https://maps.google.com/?ll=38.882147,-76.99017 } else if (url.searchParams.has("ll")) {
// https://maps.google.com/?ll=38.882147,-76.99017
const [mlat, mlon] = url.searchParams.get("ll").split(",") const [mlat, mlon] = url.searchParams.get("ll").split(",")
return `${randomInstance}/search?query=${mlat}%2C${mlon}` return `${randomInstance}/search?query=${mlat}%2C${mlon}`
} else if (url.searchParams.has("viewpoint")) { // https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.857832,2.295226&heading=-45&pitch=38&fov=80 } else if (url.searchParams.has("viewpoint")) {
// https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.857832,2.295226&heading=-45&pitch=38&fov=80
const [mlat, mlon] = url.searchParams.get("viewpoint").split(",") const [mlat, mlon] = url.searchParams.get("viewpoint").split(",")
return `${randomInstance}/search?query=${mlat}%2C${mlon}` return `${randomInstance}/search?query=${mlat}%2C${mlon}`
} else { } else {
@ -213,7 +227,8 @@ function rewrite(url, frontend, randomInstance) {
return `${randomInstance}/${mapCentre}&${prefsEncoded(prefs)}` return `${randomInstance}/${mapCentre}&${prefsEncoded(prefs)}`
} }
case "breezeWiki": { case "breezeWiki": {
let wiki, urlpath = "" let wiki,
urlpath = ""
if (url.hostname.match(/^[a-zA-Z0-9-]+\.(?:fandom|wikia)\.com/)) { if (url.hostname.match(/^[a-zA-Z0-9-]+\.(?:fandom|wikia)\.com/)) {
wiki = url.hostname.match(/^[a-zA-Z0-9-]+(?=\.(?:fandom|wikia)\.com)/) wiki = url.hostname.match(/^[a-zA-Z0-9-]+(?=\.(?:fandom|wikia)\.com)/)
if (wiki == "www" || !wiki) wiki = "" if (wiki == "www" || !wiki) wiki = ""
@ -228,12 +243,15 @@ function rewrite(url, frontend, randomInstance) {
} }
} }
if (url.href.search(/Special:Search\?query/) > -1) { if (url.href.search(/Special:Search\?query/) > -1) {
return `${randomInstance}${wiki}${urlpath}${url.search}`.replace(/Special:Search\?query/, "search?q").replace(/\/wiki/, "") return `${randomInstance}${wiki}${urlpath}${url.search}`
.replace(/Special:Search\?query/, "search?q")
.replace(/\/wiki/, "")
} }
return `${randomInstance}${wiki}${urlpath}${url.search}` return `${randomInstance}${wiki}${urlpath}${url.search}`
} }
case "rimgo": case "rimgo":
if (url.href.search(/^https?:\/{2}(?:[im]\.)?stack\./) > -1) return `${randomInstance}/stack${url.pathname}${url.search}` if (url.href.search(/^https?:\/{2}(?:[im]\.)?stack\./) > -1)
return `${randomInstance}/stack${url.pathname}${url.search}`
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "redlib": case "redlib":
case "libreddit": { case "libreddit": {
@ -257,18 +275,19 @@ function rewrite(url, frontend, randomInstance) {
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "neuters": { case "neuters": {
const p = url.pathname const p = url.pathname
if (p.startsWith('/article/') || p.startsWith('/pf/') || p.startsWith('/arc/') || p.startsWith('/resizer/')) { if (p.startsWith("/article/") || p.startsWith("/pf/") || p.startsWith("/arc/") || p.startsWith("/resizer/")) {
return randomInstance return randomInstance
} }
return `${randomInstance}${p}` return `${randomInstance}${p}`
} }
case "dumb": case "dumb":
if (url.pathname.endsWith('-lyrics')) return `${randomInstance}${url.pathname}` if (url.pathname.endsWith("-lyrics")) return `${randomInstance}${url.pathname}`
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "intellectual": case "intellectual":
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "ruralDictionary": case "ruralDictionary":
if (!url.pathname.includes('/define.php') && !url.pathname.includes('/random.php') && url.pathname != '/') return randomInstance if (!url.pathname.includes("/define.php") && !url.pathname.includes("/random.php") && url.pathname != "/")
return randomInstance
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "anonymousOverflow": { case "anonymousOverflow": {
if (url.hostname == "stackoverflow.com") { if (url.hostname == "stackoverflow.com") {
@ -285,7 +304,9 @@ function rewrite(url, frontend, randomInstance) {
const subdomain = regex[1] const subdomain = regex[1]
return `${randomInstance}/exchange/${subdomain}${url.pathname}${url.search}` return `${randomInstance}/exchange/${subdomain}${url.pathname}${url.search}`
} }
const notExchangeRegex = url.hostname.match(/(?:[a-zA-Z]+\.)?(?:askubuntu\.com|mathoverflow\.net|serverfault\.com|stackapps\.com|superuser\.com|stackoverflow\.com)/) const notExchangeRegex = url.hostname.match(
/(?:[a-zA-Z]+\.)?(?:askubuntu\.com|mathoverflow\.net|serverfault\.com|stackapps\.com|superuser\.com|stackoverflow\.com)/
)
if (notExchangeRegex) { if (notExchangeRegex) {
return `${randomInstance}/exchange/${notExchangeRegex[0]}${url.pathname}${url.search}` return `${randomInstance}/exchange/${notExchangeRegex[0]}${url.pathname}${url.search}`
} }
@ -304,7 +325,7 @@ function rewrite(url, frontend, randomInstance) {
return `${randomInstance}${url.pathname}${url.search}${url.hash}` return `${randomInstance}${url.pathname}${url.search}${url.hash}`
} }
case "proxiTok": case "proxiTok":
if (url.pathname.startsWith('/email')) return randomInstance if (url.pathname.startsWith("/email")) return randomInstance
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "waybackClassic": { case "waybackClassic": {
const regex = /^\/\web\/(?:[0-9]+)?\*\/(.*)/.exec(url.pathname) const regex = /^\/\web\/(?:[0-9]+)?\*\/(.*)/.exec(url.pathname)
@ -315,7 +336,7 @@ function rewrite(url, frontend, randomInstance) {
const regex2 = /(^\/\web\/([0-9]+)\/.*)/.exec(url.pathname) const regex2 = /(^\/\web\/([0-9]+)\/.*)/.exec(url.pathname)
if (regex2) { if (regex2) {
let link = regex2[1] let link = regex2[1]
link = link.replace(regex2[2], regex2[2] + 'if_') link = link.replace(regex2[2], regex2[2] + "if_")
return `https://web.archive.org${link}` return `https://web.archive.org${link}`
} }
return return
@ -325,17 +346,18 @@ function rewrite(url, frontend, randomInstance) {
if (url.hostname == "raw.githubusercontent.com") return `${randomInstance}/raw${url.pathname}${url.search}` if (url.hostname == "raw.githubusercontent.com") return `${randomInstance}/raw${url.pathname}${url.search}`
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "mikuInvidious": case "mikuInvidious":
if (url.hostname == "bilibili.com" || url.hostname == "www.bilibili.com" || url.hostname == 'b23.tv') return `${randomInstance}${url.pathname}${url.search}` if (url.hostname == "bilibili.com" || url.hostname == "www.bilibili.com" || url.hostname == "b23.tv")
return `${randomInstance}${url.pathname}${url.search}`
if (url.hostname == "space.bilibili.com") return `${randomInstance}/space${url.pathname}${url.search}` if (url.hostname == "space.bilibili.com") return `${randomInstance}/space${url.pathname}${url.search}`
case "tent": { case "tent": {
if (url.hostname == 'bandcamp.com' && url.pathname == '/search') { if (url.hostname == "bandcamp.com" && url.pathname == "/search") {
const query = url.searchParams.get('q') const query = url.searchParams.get("q")
return `${randomInstance}/search.php?query=${encodeURIComponent(query)}` return `${randomInstance}/search.php?query=${encodeURIComponent(query)}`
} }
if (url.hostname.endsWith('bandcamp.com')) { if (url.hostname.endsWith("bandcamp.com")) {
const regex = /^(.*)\.bandcamp\.com/.exec(url.hostname) const regex = /^(.*)\.bandcamp\.com/.exec(url.hostname)
const artist = regex[1] const artist = regex[1]
if (url.pathname == '/' || url.pathname == '/music') { if (url.pathname == "/" || url.pathname == "/music") {
return `${randomInstance}/artist.php?name=${artist}` return `${randomInstance}/artist.php?name=${artist}`
} else { } else {
const regex = /^\/(.*)\/(.*)/.exec(url.pathname) const regex = /^\/(.*)\/(.*)/.exec(url.pathname)
@ -346,18 +368,18 @@ function rewrite(url, frontend, randomInstance) {
} }
} }
} }
if (url.hostname == 'f4.bcbits.com') { if (url.hostname == "f4.bcbits.com") {
const regex = /\/img\/(.*)/.exec(url.pathname) const regex = /\/img\/(.*)/.exec(url.pathname)
const image = regex[1] const image = regex[1]
return `${randomInstance}/image.php?file=${image}` return `${randomInstance}/image.php?file=${image}`
} }
if (url.hostname == 't4.bcbits.com') { if (url.hostname == "t4.bcbits.com") {
const regex = /\/stream\/(.*)\/(.*)\/(.*)/.exec(url.pathname) const regex = /\/stream\/(.*)\/(.*)\/(.*)/.exec(url.pathname)
if (regex) { if (regex) {
const directory = regex[1] const directory = regex[1]
const format = regex[2] const format = regex[2]
const file = regex[3] const file = regex[3]
const token = url.searchParams.get('token') const token = url.searchParams.get("token")
return `${randomInstance}/audio.php/?directory=${directory}&format=${format}&file=${file}&token=${encodeURIComponent(token)}` return `${randomInstance}/audio.php/?directory=${directory}&format=${format}&file=${file}&token=${encodeURIComponent(token)}`
} }
} }
@ -388,52 +410,51 @@ function rewrite(url, frontend, randomInstance) {
} }
case "invidious": { case "invidious": {
url.searchParams.delete("si") url.searchParams.delete("si")
if (url.hostname == "youtu.be" || url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live")) { if (url.hostname == "youtu.be" || (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live"))) {
const watch = url.pathname.substring(url.pathname.lastIndexOf('/') + 1) const watch = url.pathname.substring(url.pathname.lastIndexOf("/") + 1)
return `${randomInstance}/watch?v=${watch}${url.search.replace("?", "&")}` return `${randomInstance}/watch?v=${watch}${url.search.replace("?", "&")}`
} }
if (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/redirect?")) if (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/redirect?")) return url.href
return url.href
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
} }
case "freetubeMusic": { case "freetubeMusic": {
if (url.hostname == "youtu.be" || url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live")) { if (url.hostname == "youtu.be" || (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live"))) {
const watch = url.pathname.substring(url.pathname.lastIndexOf('/') + 1) const watch = url.pathname.substring(url.pathname.lastIndexOf("/") + 1)
return `freetube://youtube.com/watch?v=${watch}` return `freetube://youtube.com/watch?v=${watch}`
} }
return 'freetube://' + url.href return "freetube://" + url.href
} }
case "invidiousMusic": { case "invidiousMusic": {
if (url.hostname == "youtu.be" || url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live")) { if (url.hostname == "youtu.be" || (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live"))) {
const watch = url.pathname.substring(url.pathname.lastIndexOf('/') + 1) const watch = url.pathname.substring(url.pathname.lastIndexOf("/") + 1)
return `${randomInstance}/watch?v=${watch}` return `${randomInstance}/watch?v=${watch}`
} }
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
} }
case 'materialious': { case "materialious": {
url.searchParams.delete('si') url.searchParams.delete("si")
if (url.hostname == 'youtu.be' || (url.hostname.endsWith('youtube.com') && url.pathname.startsWith('/live'))) { if (url.hostname == "youtu.be" || (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live"))) {
const watch = url.pathname.substring(url.pathname.lastIndexOf('/') + 1) const watch = url.pathname.substring(url.pathname.lastIndexOf("/") + 1)
return `${randomInstance}/watch/${watch}${url.search.replace('?', '&')}` return `${randomInstance}/watch/${watch}${url.search.replace("?", "&")}`
} }
if (url.hostname.endsWith("youtube.com")) { if (url.hostname.endsWith("youtube.com")) {
if (url.pathname.startsWith('/watch')) { if (url.pathname.startsWith("/watch")) {
if (url.searchParams.has('v')) { if (url.searchParams.has("v")) {
const watch = url.searchParams.get('v') const watch = url.searchParams.get("v")
url.searchParams.delete('v') url.searchParams.delete("v")
return `${randomInstance}/watch/${watch}${url.search.replace('?', '&')}` return `${randomInstance}/watch/${watch}${url.search.replace("?", "&")}`
} }
return `${randomInstance}/watch/${url.search.replace('?', '&')}` return `${randomInstance}/watch/${url.search.replace("?", "&")}`
} }
if (url.pathname.startsWith('/results')) { if (url.pathname.startsWith("/results")) {
if (url.searchParams.has('search_query')) { if (url.searchParams.has("search_query")) {
const search = url.searchParams.get('search_query') const search = url.searchParams.get("search_query")
url.searchParams.delete('search_query') url.searchParams.delete("search_query")
return `${randomInstance}/search/${search}${url.search.replace('?', '&')}` return `${randomInstance}/search/${search}${url.search.replace("?", "&")}`
} }
return `${randomInstance}/search/${url.search.replace('?', '&')}` return `${randomInstance}/search/${url.search.replace("?", "&")}`
} }
if (url.pathname.startsWith('/redirect?')) { if (url.pathname.startsWith("/redirect?")) {
return url.href return url.href
} }
} }
@ -453,7 +474,7 @@ function rewrite(url, frontend, randomInstance) {
if (url.pathname.startsWith("/watch")) return `${randomInstance}/stream?url=${encodeURIComponent(url.href)}` if (url.pathname.startsWith("/watch")) return `${randomInstance}/stream?url=${encodeURIComponent(url.href)}`
return randomInstance return randomInstance
case "tuboSoundcloud": case "tuboSoundcloud":
if (url.pathname == '/') return `${randomInstance}?kiosk?serviceId=1` if (url.pathname == "/") return `${randomInstance}?kiosk?serviceId=1`
if (url.pathname.match(/^\/[^\/]+(\/$|$)/)) return `${randomInstance}/channel?url=${encodeURIComponent(url.href)}` if (url.pathname.match(/^\/[^\/]+(\/$|$)/)) return `${randomInstance}/channel?url=${encodeURIComponent(url.href)}`
if (url.pathname.match(/^\/[^\/]+\/[^\/]+/)) return `${randomInstance}/stream?url=${encodeURIComponent(url.href)}` if (url.pathname.match(/^\/[^\/]+\/[^\/]+/)) return `${randomInstance}/stream?url=${encodeURIComponent(url.href)}`
return randomInstance return randomInstance
@ -463,9 +484,9 @@ function rewrite(url, frontend, randomInstance) {
return `${randomInstance}${url.pathname}${url.search}` return `${randomInstance}${url.pathname}${url.search}`
case "tekstoLibre": case "tekstoLibre":
return `${randomInstance}/?${url.pathname.slice(1)}`; return `${randomInstance}/?${url.pathname.slice(1)}`
case "skyview": case "skyview":
if (url.pathname == '/') return randomInstance if (url.pathname == "/") return randomInstance
return `${randomInstance}?url=${encodeURIComponent(url.href)}` return `${randomInstance}?url=${encodeURIComponent(url.href)}`
case "nitter": { case "nitter": {
let search = new URLSearchParams(url.search) let search = new URLSearchParams(url.search)
@ -487,7 +508,8 @@ function rewrite(url, frontend, randomInstance) {
return `${randomInstance}/pic${url.pathname}${search}` return `${randomInstance}/pic${url.pathname}${search}`
} }
} }
if (url.pathname.split("/").includes("tweets")) return `${randomInstance}${url.pathname.replace("/tweets", "")}${search}` if (url.pathname.split("/").includes("tweets"))
return `${randomInstance}${url.pathname.replace("/tweets", "")}${search}`
if (url.host == "t.co") return `${randomInstance}/t.co${url.pathname}` if (url.host == "t.co") return `${randomInstance}/t.co${url.pathname}`
return `${randomInstance}${url.pathname}${search}#m` return `${randomInstance}${url.pathname}${search}#m`
} }
@ -501,12 +523,13 @@ function rewrite(url, frontend, randomInstance) {
const blogregex = /^(?:www\.)?([a-z\d-]+)\.tumblr\.com/.exec(url.hostname) // <blog>.tumblr.com const blogregex = /^(?:www\.)?([a-z\d-]+)\.tumblr\.com/.exec(url.hostname) // <blog>.tumblr.com
if (blogregex) { if (blogregex) {
const blog_name = blogregex[1]; const blog_name = blogregex[1]
// Under the <blog>.tumblr.com domain posts are under a /post path // Under the <blog>.tumblr.com domain posts are under a /post path
if (url.pathname.startsWith("/post")) return `${randomInstance}/${blog_name}${url.pathname.slice(5)}${url.search}` if (url.pathname.startsWith("/post"))
else return `${randomInstance}/${blog_name}${url.pathname}${url.search}`; return `${randomInstance}/${blog_name}${url.pathname.slice(5)}${url.search}`
else return `${randomInstance}/${blog_name}${url.pathname}${url.search}`
} }
return `${randomInstance}${url.pathname}${url.search}`; return `${randomInstance}${url.pathname}${url.search}`
} }
case "piped": case "piped":
case "pipedMaterial": case "pipedMaterial":
@ -536,7 +559,11 @@ function redirect(url, type, initiator, forceRedirection, incognito) {
frontend = options[service].frontend frontend = options[service].frontend
if (config.services[service].frontends[frontend].desktopApp && type != "main_frame" && options[service].redirectType != "main_frame") if (
config.services[service].frontends[frontend].desktopApp &&
type != "main_frame" &&
options[service].redirectType != "main_frame"
)
frontend = options[service].embedFrontend frontend = options[service].embedFrontend
if (!regexArray(service, url, config, frontend)) { if (!regexArray(service, url, config, frontend)) {
@ -545,11 +572,11 @@ function redirect(url, type, initiator, forceRedirection, incognito) {
} }
if ( if (
config.services[service].embeddable config.services[service].embeddable &&
&& type != options[service].redirectType &&
type != options[service].redirectType && options[service].redirectType != "both" options[service].redirectType != "both"
) { ) {
if (options[service].unsupportedUrls == 'block') return 'CANCEL' if (options[service].unsupportedUrls == "block") return "CANCEL"
return return
} }
@ -588,10 +615,8 @@ function computeService(url, returnFrontend) {
} else { } else {
for (const frontend in config.services[service].frontends) { for (const frontend in config.services[service].frontends) {
if (all(service, frontend, options, config).includes(utils.protocolHost(url))) { if (all(service, frontend, options, config).includes(utils.protocolHost(url))) {
if (returnFrontend) if (returnFrontend) resolve([service, frontend, utils.protocolHost(url)])
resolve([service, frontend, utils.protocolHost(url)]) else resolve(service)
else
resolve(service)
return return
} }
} }
@ -699,61 +724,61 @@ async function reverse(url) {
} }
const defaultInstances = { const defaultInstances = {
'invidious': ['https://inv.vern.cc'], invidious: ["https://inv.vern.cc"],
'materialious': ['https://app.materialio.us'], materialious: ["https://app.materialio.us"],
'viewtube': ['https://viewtube.io'], viewtube: ["https://viewtube.io"],
'piped': ['https://pipedapi-libre.kavin.rocks'], piped: ["https://pipedapi-libre.kavin.rocks"],
'pipedMaterial': ['https://piped-material.xn--17b.net'], pipedMaterial: ["https://piped-material.xn--17b.net"],
'cloudtube': ['https://tube.cadence.moe'], cloudtube: ["https://tube.cadence.moe"],
'lightTube': ['https://tube.kuylar.dev'], lightTube: ["https://tube.kuylar.dev"],
'poketube': ['https://poketube.fun'], poketube: ["https://poketube.fun"],
'proxiTok': ['https://proxitok.pabloferreiro.es'], proxiTok: ["https://proxitok.pabloferreiro.es"],
'redlib': ['https://safereddit.com'], redlib: ["https://safereddit.com"],
'libreddit': ['https://libreddit.spike.codes'], libreddit: ["https://libreddit.spike.codes"],
'teddit': ['https://teddit.net'], teddit: ["https://teddit.net"],
'scribe': ['https://scribe.rip'], scribe: ["https://scribe.rip"],
'libMedium': ['https://md.vern.cc'], libMedium: ["https://md.vern.cc"],
'quetre': ['https://quetre.iket.me'], quetre: ["https://quetre.iket.me"],
'libremdb': ['https://libremdb.iket.me'], libremdb: ["https://libremdb.iket.me"],
'simplyTranslate': ['https://simplytranslate.org'], simplyTranslate: ["https://simplytranslate.org"],
'mozhi': ['https://mozhi.aryak.me'], mozhi: ["https://mozhi.aryak.me"],
'searxng': ['https://search.bus-hit.me'], searxng: ["https://search.bus-hit.me"],
'4get': ['https://4get.ca'], "4get": ["https://4get.ca"],
'rimgo': ['https://rimgo.vern.cc'], rimgo: ["https://rimgo.vern.cc"],
'hyperpipe': ['https://hyperpipe.surge.sh'], hyperpipe: ["https://hyperpipe.surge.sh"],
'osm': ['https://www.openstreetmap.org'], osm: ["https://www.openstreetmap.org"],
'breezeWiki': ['https://breezewiki.com'], breezeWiki: ["https://breezewiki.com"],
'neuters': ['https://neuters.de'], neuters: ["https://neuters.de"],
'dumb': ['https://dm.vern.cc'], dumb: ["https://dm.vern.cc"],
"intellectual": ['https://intellectual.insprill.net'], intellectual: ["https://intellectual.insprill.net"],
'ruralDictionary': ['https://rd.vern.cc'], ruralDictionary: ["https://rd.vern.cc"],
'anonymousOverflow': ['https://code.whatever.social'], anonymousOverflow: ["https://code.whatever.social"],
'biblioReads': ['https://biblioreads.ml'], biblioReads: ["https://biblioreads.ml"],
'wikiless': ['https://wikiless.org'], wikiless: ["https://wikiless.org"],
'suds': ['https://sd.vern.cc'], suds: ["https://sd.vern.cc"],
'unfunny': ['https://uf.vern.cc'], unfunny: ["https://uf.vern.cc"],
'soprano': ['https://sp.vern.cc'], soprano: ["https://sp.vern.cc"],
'meme': ['https://mm.vern.cc'], meme: ["https://mm.vern.cc"],
'waybackClassic': ['https://wayback-classic.net'], waybackClassic: ["https://wayback-classic.net"],
'gothub': ['https://gh.odyssey346.dev'], gothub: ["https://gh.odyssey346.dev"],
'mikuInvidious': ['https://mikuinv.resrv.org'], mikuInvidious: ["https://mikuinv.resrv.org"],
"tent": ['https://tent.sny.sh'], tent: ["https://tent.sny.sh"],
"wolfreeAlpha": ['https://gqq.gitlab.io', 'https://uqq.gitlab.io'], wolfreeAlpha: ["https://gqq.gitlab.io", "https://uqq.gitlab.io"],
"laboratory": ['https://lab.vern.cc'], laboratory: ["https://lab.vern.cc"],
'binternet': ['https://bn.bloat.cat'], binternet: ["https://bn.bloat.cat"],
'pixivFe': ['https://pixivfe.exozy.me'], pixivFe: ["https://pixivfe.exozy.me"],
'indestructables': ['https://indestructables.private.coffee'], indestructables: ["https://indestructables.private.coffee"],
'destructables': ['https://ds.vern.cc'], destructables: ["https://ds.vern.cc"],
'safetwitch': ['https://safetwitch.drgns.space'], safetwitch: ["https://safetwitch.drgns.space"],
'twineo': ['https://twineo.exozy.me'], twineo: ["https://twineo.exozy.me"],
'proxigram': ['https://ig.opnxng.com'], proxigram: ["https://ig.opnxng.com"],
'tuboYoutube': ['https://tubo.migalmoreno.com'], tuboYoutube: ["https://tubo.migalmoreno.com"],
'tuboSoundcloud': ['https://tubo.migalmoreno.com'], tuboSoundcloud: ["https://tubo.migalmoreno.com"],
'tekstoLibre': ['https://davilarek.github.io/TekstoLibre'], tekstoLibre: ["https://davilarek.github.io/TekstoLibre"],
'skyview': ['https://skyview.social'], skyview: ["https://skyview.social"],
'priviblur': ['https://pb.bloat.cat'], priviblur: ["https://pb.bloat.cat"],
'nitter': ['https://nitter.privacydev.net'], nitter: ["https://nitter.privacydev.net"],
'pasted': ['https://pasted.drakeerv.com'], pasted: ["https://pasted.drakeerv.com"],
} }
function initDefaults() { function initDefaults() {
@ -778,14 +803,12 @@ function initDefaults() {
} }
options.theme = "detect" options.theme = "detect"
options.popupServices = ["youtube", "tiktok", "imgur", "reddit", "quora", "translate", "maps"] options.popupServices = ["youtube", "tiktok", "imgur", "reddit", "quora", "translate", "maps"]
options.fetchInstances = 'github' options.fetchInstances = "github"
options.redirectOnlyInIncognito = false options.redirectOnlyInIncognito = false
options = { ...options, ...defaultInstances } options = { ...options, ...defaultInstances }
browser.storage.local.set({ options }, browser.storage.local.set({ options }, () => resolve())
() => resolve()
)
}) })
}) })
} }
@ -830,19 +853,19 @@ function processUpdate() {
for (const frontend of options.popupServices) { for (const frontend of options.popupServices) {
if (!Object.keys(config.services).includes(frontend)) { if (!Object.keys(config.services).includes(frontend)) {
const i = options.popupServices.indexOf(frontend); const i = options.popupServices.indexOf(frontend)
if (i > -1) options.popupServices.splice(i, 1); if (i > -1) options.popupServices.splice(i, 1)
} }
} }
} }
const general = ['theme', 'popupServices', 'fetchInstances', 'redirectOnlyInIncognito'] const general = ["theme", "popupServices", "fetchInstances", "redirectOnlyInIncognito"]
const combined = [ const combined = [
...Object.keys(config.services), ...Object.keys(config.services),
...frontends, ...frontends,
...general, ...general,
'exceptions', "exceptions",
'popupServices', "popupServices",
'version', "version",
] ]
for (const key in options) { for (const key in options) {
if (combined.indexOf(key) < 0) { if (combined.indexOf(key) < 0) {
@ -864,13 +887,13 @@ async function copyRaw(url) {
if (!isChrome) { if (!isChrome) {
navigator.clipboard.writeText(newUrl) navigator.clipboard.writeText(newUrl)
} else { } else {
var copyFrom = document.createElement("textarea"); var copyFrom = document.createElement("textarea")
copyFrom.textContent = newUrl; copyFrom.textContent = newUrl
document.body.appendChild(copyFrom); document.body.appendChild(copyFrom)
copyFrom.select() copyFrom.select()
document.execCommand('copy') document.execCommand("copy")
copyFrom.blur(); copyFrom.blur()
document.body.removeChild(copyFrom); document.body.removeChild(copyFrom)
} }
} }
} }
@ -885,7 +908,7 @@ function isException(url) {
if (exceptions.url) { if (exceptions.url) {
for (let item of exceptions.url) { for (let item of exceptions.url) {
item = new URL(item) item = new URL(item)
item = item.href.replace(/^http:\/\//, 'https://') item = item.href.replace(/^http:\/\//, "https://")
if (item == url.href) return true if (item == url.href) return true
} }
} }
@ -904,5 +927,5 @@ export default {
processUpdate, processUpdate,
copyRaw, copyRaw,
switchInstance, switchInstance,
isException isException,
} }

View File

@ -14,10 +14,10 @@ function getRandomInstance(instances) {
* @returns {T} * @returns {T}
*/ */
function getNextInstance(currentInstanceUrl, instances) { function getNextInstance(currentInstanceUrl, instances) {
const currentInstanceIndex = instances.indexOf(currentInstanceUrl); const currentInstanceIndex = instances.indexOf(currentInstanceUrl)
if (currentInstanceIndex === -1) return getRandomInstance(instances); if (currentInstanceIndex === -1) return getRandomInstance(instances)
const nextInstanceIndex = (currentInstanceIndex + 1) % instances.length; const nextInstanceIndex = (currentInstanceIndex + 1) % instances.length
return instances[nextInstanceIndex]; return instances[nextInstanceIndex]
} }
/** /**
@ -32,7 +32,8 @@ function camelCase(str) {
*/ */
function protocolHost(url) { function protocolHost(url) {
if (url.username && url.password) return `${url.protocol}//${url.username}:${url.password}@${url.host}` if (url.username && url.password) return `${url.protocol}//${url.username}:${url.password}@${url.host}`
if (url.pathname == "/TekstoLibre/" && url.host.endsWith("github.io")) // workaround 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}${url.pathname.slice(0, -1)}`
return `${url.protocol}//${url.host}` return `${url.protocol}//${url.host}`
} }
@ -88,14 +89,15 @@ function getPingCache() {
function getBlacklist(options) { function getBlacklist(options) {
return new Promise(resolve => { return new Promise(resolve => {
let url let url
if (options.fetchInstances == 'github') url = 'https://raw.githubusercontent.com/libredirect/instances/main/blacklist.json' if (options.fetchInstances == "github")
else if (options.fetchInstances == 'codeberg') url = 'https://codeberg.org/LibRedirect/instances/raw/branch/main/blacklist.json' url = "https://raw.githubusercontent.com/libredirect/instances/main/blacklist.json"
else return resolve('disabled') else if (options.fetchInstances == "codeberg")
url = "https://codeberg.org/LibRedirect/instances/raw/branch/main/blacklist.json"
else return resolve("disabled")
const http = new XMLHttpRequest() const http = new XMLHttpRequest()
http.open("GET", url, true) http.open("GET", url, true)
http.onreadystatechange = () => { http.onreadystatechange = () => {
if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) resolve(JSON.parse(http.responseText))
resolve(JSON.parse(http.responseText))
} }
http.onerror = () => resolve() http.onerror = () => resolve()
http.ontimeout = () => resolve() http.ontimeout = () => resolve()
@ -106,14 +108,15 @@ function getBlacklist(options) {
function getList(options) { function getList(options) {
return new Promise(resolve => { return new Promise(resolve => {
let url let url
if (options.fetchInstances == 'github') url = 'https://raw.githubusercontent.com/libredirect/instances/main/data.json' if (options.fetchInstances == "github")
else if (options.fetchInstances == 'codeberg') url = 'https://codeberg.org/LibRedirect/instances/raw/branch/main/data.json' url = "https://raw.githubusercontent.com/libredirect/instances/main/data.json"
else return resolve('disabled') else if (options.fetchInstances == "codeberg")
url = "https://codeberg.org/LibRedirect/instances/raw/branch/main/data.json"
else return resolve("disabled")
const http = new XMLHttpRequest() const http = new XMLHttpRequest()
http.open("GET", url, true) http.open("GET", url, true)
http.onreadystatechange = () => { http.onreadystatechange = () => {
if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) if (http.status === 200 && http.readyState == XMLHttpRequest.DONE) return resolve(JSON.parse(http.responseText))
return resolve(JSON.parse(http.responseText))
} }
http.onerror = () => resolve() http.onerror = () => resolve()
http.ontimeout = () => resolve() http.ontimeout = () => resolve()

View File

@ -33,30 +33,21 @@
"url": "https://materialio.us/" "url": "https://materialio.us/"
}, },
"piped": { "piped": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "Piped", "name": "Piped",
"embeddable": true, "embeddable": true,
"instanceList": true, "instanceList": true,
"url": "https://github.com/TeamPiped/Piped" "url": "https://github.com/TeamPiped/Piped"
}, },
"pipedMaterial": { "pipedMaterial": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "Piped-Material", "name": "Piped-Material",
"embeddable": false, "embeddable": false,
"instanceList": true, "instanceList": true,
"url": "https://github.com/mmjee/Piped-Material" "url": "https://github.com/mmjee/Piped-Material"
}, },
"poketube": { "poketube": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "PokeTube", "name": "PokeTube",
"embeddable": true, "embeddable": true,
"instanceList": true, "instanceList": true,
@ -67,10 +58,7 @@
"embeddable": false, "embeddable": false,
"instanceList": true, "instanceList": true,
"url": "https://sr.ht/~cadence/tube", "url": "https://sr.ht/~cadence/tube",
"excludeTargets": [ "excludeTargets": [2, 3]
2,
3
]
}, },
"lightTube": { "lightTube": {
"name": "LightTube", "name": "LightTube",
@ -83,16 +71,10 @@
"embeddable": false, "embeddable": false,
"instanceList": true, "instanceList": true,
"url": "https://git.migalmoreno.com/tubo/about/", "url": "https://git.migalmoreno.com/tubo/about/",
"excludeTargets": [ "excludeTargets": [2, 3]
2,
3
]
}, },
"freetube": { "freetube": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "FreeTube", "name": "FreeTube",
"embeddable": false, "embeddable": false,
"desktopApp": true, "desktopApp": true,
@ -100,10 +82,7 @@
"url": "https://github.com/FreeTubeApp/FreeTube" "url": "https://github.com/FreeTubeApp/FreeTube"
}, },
"yattee": { "yattee": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "Yattee", "name": "Yattee",
"embeddable": false, "embeddable": false,
"desktopApp": true, "desktopApp": true,
@ -111,10 +90,7 @@
"url": "https://github.com/yattee/yattee" "url": "https://github.com/yattee/yattee"
}, },
"freetubePwa": { "freetubePwa": {
"excludeTargets": [ "excludeTargets": [2, 3],
2,
3
],
"name": "FreeTube PWA", "name": "FreeTube PWA",
"embeddable": false, "embeddable": false,
"instanceList": false, "instanceList": false,
@ -168,9 +144,7 @@
"url": "https://github.com/FreeTubeApp/FreeTube" "url": "https://github.com/FreeTubeApp/FreeTube"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}music\\.youtube\\.com\\/"],
"^https?:\\/{2}music\\.youtube\\.com\\/"
],
"name": "YT Music", "name": "YT Music",
"options": { "options": {
"enabled": false, "enabled": false,
@ -218,9 +192,7 @@
"url": "https://github.com/badlogic/skyview" "url": "https://github.com/badlogic/skyview"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}bsky\\.app\\/"],
"^https?:\\/{2}bsky\\.app\\/"
],
"name": "Bluesky", "name": "Bluesky",
"options": { "options": {
"enabled": false, "enabled": false,
@ -309,9 +281,7 @@
"localhost": false "localhost": false
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.|clips\\.)?twitch\\.(tv|com)\\/"],
"^https?:\\/{2}(www\\.|clips\\.)?twitch\\.(tv|com)\\/"
],
"name": "Twitch", "name": "Twitch",
"options": { "options": {
"enabled": false, "enabled": false,
@ -333,9 +303,7 @@
"localhost": true "localhost": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?tiktok\\.com\\/"],
"^https?:\\/{2}(www\\.)?tiktok\\.com\\/"
],
"name": "TikTok", "name": "TikTok",
"options": { "options": {
"enabled": false, "enabled": false,
@ -355,9 +323,7 @@
"localhost": false "localhost": false
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?instagram\\.com"],
"^https?:\\/{2}(www\\.)?instagram\\.com"
],
"name": "Instagram", "name": "Instagram",
"options": { "options": {
"enabled": false, "enabled": false,
@ -377,9 +343,7 @@
"localhost": true "localhost": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.|m\\.)?imdb\\.com"],
"^https?:\\/{2}(www\\.|m\\.)?imdb\\.com"
],
"name": "IMDb", "name": "IMDb",
"options": { "options": {
"enabled": false, "enabled": false,
@ -398,10 +362,7 @@
"url": "https://0xacab.org/johnxina/mikuinvidious" "url": "https://0xacab.org/johnxina/mikuinvidious"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.|space\\.)?bilibili\\.com\\/", "^https?:\\/{2}b23\\.tv\\/"],
"^https?:\\/{2}(www\\.|space\\.)?bilibili\\.com\\/",
"^https?:\\/{2}b23\\.tv\\/"
],
"name": "Bilibili", "name": "Bilibili",
"options": { "options": {
"enabled": false, "enabled": false,
@ -420,9 +381,7 @@
"url": "https://codeberg.org/VnPower/pixivfe" "url": "https://codeberg.org/VnPower/pixivfe"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?pixiv\\.net\\/"],
"^https?:\\/{2}(www\\.)?pixiv\\.net\\/"
],
"options": { "options": {
"enabled": false, "enabled": false,
"unsupportedUrls": "bypass", "unsupportedUrls": "bypass",
@ -439,9 +398,7 @@
"url": "https://breezewiki.com" "url": "https://breezewiki.com"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}([a-zA-Z0-9-]+\\.)?(fandom|wikia)\\.com(?=\\/wiki|\\/?$)"],
"^https?:\\/{2}([a-zA-Z0-9-]+\\.)?(fandom|wikia)\\.com(?=\\/wiki|\\/?$)"
],
"name": "Fandom", "name": "Fandom",
"options": { "options": {
"enabled": false, "enabled": false,
@ -462,9 +419,7 @@
"embeddable": true "embeddable": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}([im]\\.)?(stack\\.)?imgur\\.(com|io)\\/"],
"^https?:\\/{2}([im]\\.)?(stack\\.)?imgur\\.(com|io)\\/"
],
"name": "Imgur", "name": "Imgur",
"options": { "options": {
"enabled": false, "enabled": false,
@ -487,10 +442,7 @@
"embeddable": true "embeddable": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}i\\.pinimg\\.com", "^https?:\\/{2}(www\\.)?pinterest\\.com"],
"^https?:\\/{2}i\\.pinimg\\.com",
"^https?:\\/{2}(www\\.)?pinterest\\.com"
],
"options": { "options": {
"enabled": false, "enabled": false,
"unsupportedUrls": "bypass", "unsupportedUrls": "bypass",
@ -510,9 +462,7 @@
"url": "https://git.migalmoreno.com/tubo/about/" "url": "https://git.migalmoreno.com/tubo/about/"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}soundcloud\\.com"],
"^https?:\\/{2}soundcloud\\.com"
],
"name": "SoundCloud", "name": "SoundCloud",
"options": { "options": {
"enabled": false, "enabled": false,
@ -532,10 +482,7 @@
"url": "https://forgejo.sny.sh/sun/Tent" "url": "https://forgejo.sny.sh/sun/Tent"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(.*\\.)?bandcamp\\.com\\/", "^https?:\\/{2}(f4|t4)\\.bcbits\\.com\\/"],
"^https?:\\/{2}(.*\\.)?bandcamp\\.com\\/",
"^https?:\\/{2}(f4|t4)\\.bcbits\\.com\\/"
],
"name": "Bandcamp", "name": "Bandcamp",
"options": { "options": {
"enabled": false, "enabled": false,
@ -553,9 +500,7 @@
"url": "https://github.com/Davilarek/TekstoLibre" "url": "https://github.com/Davilarek/TekstoLibre"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?tekstowo\\.pl\\/"],
"^https?:\\/{2}(www\\.)?tekstowo\\.pl\\/"
],
"name": "Tekstowo.pl", "name": "Tekstowo.pl",
"options": { "options": {
"enabled": false, "enabled": false,
@ -580,9 +525,7 @@
"localhost": false "localhost": false
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?genius\\.com\\/"],
"^https?:\\/{2}(www\\.)?genius\\.com\\/"
],
"name": "Genius", "name": "Genius",
"options": { "options": {
"enabled": false, "enabled": false,
@ -645,9 +588,7 @@
"localhost": true "localhost": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}([a-zA-Z0-9-]+\\.)*quora\\.com\\/"],
"^https?:\\/{2}([a-zA-Z0-9-]+\\.)*quora\\.com\\/"
],
"name": "Quora", "name": "Quora",
"options": { "options": {
"enabled": false, "enabled": false,
@ -734,9 +675,7 @@
"url": "https://github.com/HookedBehemoth/neuters" "url": "https://github.com/HookedBehemoth/neuters"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?reuters\\.com\\/"],
"^https?:\\/{2}(www\\.)?reuters\\.com\\/"
],
"name": "Reuters", "name": "Reuters",
"options": { "options": {
"enabled": false, "enabled": false,
@ -754,9 +693,7 @@
"url": "https://git.vern.cc/cobra/Suds" "url": "https://git.vern.cc/cobra/Suds"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?snopes\\.com\\/"],
"^https?:\\/{2}(www\\.)?snopes\\.com\\/"
],
"name": "Snopes", "name": "Snopes",
"options": { "options": {
"enabled": false, "enabled": false,
@ -774,9 +711,7 @@
"url": "https://git.vern.cc/cobra/UNfunny" "url": "https://git.vern.cc/cobra/UNfunny"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?ifunny\\.co\\/"],
"^https?:\\/{2}(www\\.)?ifunny\\.co\\/"
],
"name": "iFunny", "name": "iFunny",
"options": { "options": {
"enabled": false, "enabled": false,
@ -794,9 +729,7 @@
"url": "https://git.vern.cc/cobra/Soprano" "url": "https://git.vern.cc/cobra/Soprano"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?tenor\\.com\\/"],
"^https?:\\/{2}(www\\.)?tenor\\.com\\/"
],
"name": "Tenor", "name": "Tenor",
"options": { "options": {
"enabled": false, "enabled": false,
@ -814,9 +747,7 @@
"url": "https://git.vern.cc/cobra/MeMe" "url": "https://git.vern.cc/cobra/MeMe"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?knowyourmeme\\.com\\/"],
"^https?:\\/{2}(www\\.)?knowyourmeme\\.com\\/"
],
"name": "KnowYourMeme", "name": "KnowYourMeme",
"options": { "options": {
"enabled": false, "enabled": false,
@ -834,9 +765,7 @@
"url": "https://codeberg.org/zortazert/rural-dictionary" "url": "https://codeberg.org/zortazert/rural-dictionary"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?urbandictionary\\.com\\/"],
"^https?:\\/{2}(www\\.)?urbandictionary\\.com\\/"
],
"name": "Urban Dictionary", "name": "Urban Dictionary",
"options": { "options": {
"enabled": false, "enabled": false,
@ -855,9 +784,7 @@
"localhost": true "localhost": true
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?goodreads\\.com\\/"],
"^https?:\\/{2}(www\\.)?goodreads\\.com\\/"
],
"name": "Goodreads", "name": "Goodreads",
"options": { "options": {
"enabled": false, "enabled": false,
@ -876,9 +803,7 @@
"url": "https://git.disroot.org/wolfree" "url": "https://git.disroot.org/wolfree"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?wolframalpha\\.com\\/"],
"^https?:\\/{2}(www\\.)?wolframalpha\\.com\\/"
],
"name": "Wolfram Alpha", "name": "Wolfram Alpha",
"options": { "options": {
"enabled": false, "enabled": false,
@ -902,9 +827,7 @@
"url": "https://git.vern.cc/cobra/Destructables" "url": "https://git.vern.cc/cobra/Destructables"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}(www\\.)?instructables\\.com\\/"],
"^https?:\\/{2}(www\\.)?instructables\\.com\\/"
],
"options": { "options": {
"enabled": false, "enabled": false,
"unsupportedUrls": "bypass", "unsupportedUrls": "bypass",
@ -921,9 +844,7 @@
"url": "https://wikiless.org" "url": "https://wikiless.org"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}([a-z]+\\.)*wikipedia\\.org\\/?"],
"^https?:\\/{2}([a-z]+\\.)*wikipedia\\.org\\/?"
],
"name": "Wikipedia", "name": "Wikipedia",
"options": { "options": {
"enabled": false, "enabled": false,
@ -941,9 +862,7 @@
"url": "https://github.com/ticky/wayback-classic" "url": "https://github.com/ticky/wayback-classic"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}web\\.archive\\.org\\/"],
"^https?:\\/{2}web\\.archive\\.org\\/"
],
"name": "Wayback Machine", "name": "Wayback Machine",
"options": { "options": {
"enabled": false, "enabled": false,
@ -982,10 +901,7 @@
"url": "https://git.lolcat.ca/lolcat/4get" "url": "https://git.lolcat.ca/lolcat/4get"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}search\\.libredirect\\.invalid", "^https?:\\/{2}libredirect\\.github\\.io\\/\\?q"],
"^https?:\\/{2}search\\.libredirect\\.invalid",
"^https?:\\/{2}libredirect\\.github\\.io\\/\\?q"
],
"name": "Search", "name": "Search",
"options": { "options": {
"enabled": false, "enabled": false,
@ -1062,9 +978,7 @@
"url": "https://jitsi.org" "url": "https://jitsi.org"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}meet\\.libredirect\\.invalid\\/"],
"^https?:\\/{2}meet\\.libredirect\\.invalid\\/"
],
"options": { "options": {
"enabled": false, "enabled": false,
"unsupportedUrls": "bypass", "unsupportedUrls": "bypass",
@ -1108,9 +1022,7 @@
"url": "https://github.com/Dragynfruit/pasted" "url": "https://github.com/Dragynfruit/pasted"
} }
}, },
"targets": [ "targets": ["^https?:\\/{2}paste\\.libredirect\\.invalid"],
"^https?:\\/{2}paste\\.libredirect\\.invalid"
],
"name": "Paste Text", "name": "Paste Text",
"options": { "options": {
"enabled": false, "enabled": false,

View File

@ -22,17 +22,8 @@
"48": "assets/images/libredirect-48.png", "48": "assets/images/libredirect-48.png",
"128": "assets/images/libredirect-128.png" "128": "assets/images/libredirect-128.png"
}, },
"permissions": [ "permissions": ["webRequest", "webRequestBlocking", "storage", "clipboardWrite", "contextMenus", "<all_urls>"],
"webRequest", "optional_permissions": ["bookmarks"],
"webRequestBlocking",
"storage",
"clipboardWrite",
"contextMenus",
"<all_urls>"
],
"optional_permissions": [
"bookmarks"
],
"browser_action": { "browser_action": {
"default_title": "__MSG_extensionName__", "default_title": "__MSG_extensionName__",
"browser_style": false, "browser_style": false,

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />

View File

@ -14,9 +14,8 @@ browser.runtime.onInstalled.addListener(async details => {
await servicesHelper.initDefaults() await servicesHelper.initDefaults()
} }
browser.runtime.openOptionsPage() browser.runtime.openOptionsPage()
} } else if (details.reason == "update") {
else if (details.reason == "update") { if (details.previousVersion == "2.5.2") {
if (details.previousVersion == '2.5.2') {
await servicesHelper.upgradeOptions() await servicesHelper.upgradeOptions()
await servicesHelper.processUpdate() await servicesHelper.processUpdate()
} else { } else {
@ -33,7 +32,8 @@ browser.webRequest.onBeforeRequest.addListener(
details => { details => {
const url = new URL(details.url) const url = new URL(details.url)
const old_href = url.href const old_href = url.href
if (new RegExp(/^chrome-extension:\/{2}.*\/instances\/.*.json$/).test(url.href) && details.type == "xmlhttprequest") return if (new RegExp(/^chrome-extension:\/{2}.*\/instances\/.*.json$/).test(url.href) && details.type == "xmlhttprequest")
return
let initiator let initiator
try { try {
if (details.originUrl) initiator = new URL(details.originUrl) if (details.originUrl) initiator = new URL(details.originUrl)
@ -44,21 +44,24 @@ browser.webRequest.onBeforeRequest.addListener(
if (tabIdRedirects[details.tabId] == false) return null if (tabIdRedirects[details.tabId] == false) return null
let newUrl = servicesHelper.redirect(url, details.type, initiator, tabIdRedirects[details.tabId], details.incognito) let newUrl = servicesHelper.redirect(url, details.type, initiator, tabIdRedirects[details.tabId], details.incognito)
if (details.frameAncestors && details.frameAncestors.length > 0 && servicesHelper.isException(new URL(details.frameAncestors[0].url))) newUrl = null if (
details.frameAncestors &&
details.frameAncestors.length > 0 &&
servicesHelper.isException(new URL(details.frameAncestors[0].url))
)
newUrl = null
if (servicesHelper.isException(url)) { if (servicesHelper.isException(url)) {
if (details.type == "main_frame") if (details.type == "main_frame") newUrl = "BYPASSTAB"
newUrl = "BYPASSTAB" else return null
else
return null
} }
if (!newUrl) { if (!newUrl) {
const match = url.href.match(/^https?:\/{2}.*\.libredirect\.invalid.*/) const match = url.href.match(/^https?:\/{2}.*\.libredirect\.invalid.*/)
if (match) { if (match) {
browser.tabs.update({ browser.tabs.update({
url: browser.runtime.getURL(`/pages/messages/no_instance.html`) url: browser.runtime.getURL(`/pages/messages/no_instance.html`),
}); })
} }
} }
@ -130,42 +133,54 @@ browser.commands.onCommand.addListener(async command => {
}) })
}) })
browser.contextMenus.create({ id: "settingsTab", title: browser.i18n.getMessage("settings"), contexts: ["browser_action"] }) browser.contextMenus.create({
browser.contextMenus.create({ id: "switchInstanceTab", title: browser.i18n.getMessage("switchInstance"), contexts: ["browser_action"] }) id: "settingsTab",
browser.contextMenus.create({ id: "copyReverseTab", title: 'Copy Original', contexts: ["browser_action"] }) title: browser.i18n.getMessage("settings"),
browser.contextMenus.create({ id: "redirectTab", title: 'Redirect', contexts: ["browser_action"] }) contexts: ["browser_action"],
browser.contextMenus.create({ id: "reverseTab", title: 'Redirect To Original', contexts: ["browser_action"] }) })
browser.contextMenus.create({
id: "switchInstanceTab",
title: browser.i18n.getMessage("switchInstance"),
contexts: ["browser_action"],
})
browser.contextMenus.create({ id: "copyReverseTab", title: "Copy Original", contexts: ["browser_action"] })
browser.contextMenus.create({ id: "redirectTab", title: "Redirect", contexts: ["browser_action"] })
browser.contextMenus.create({ id: "reverseTab", title: "Redirect To Original", contexts: ["browser_action"] })
browser.contextMenus.create({ id: "redirectLink", title: 'Redirect', contexts: ["link"] }) browser.contextMenus.create({ id: "redirectLink", title: "Redirect", contexts: ["link"] })
browser.contextMenus.create({ id: "redirectLinkInNewTab", title: 'Redirect In New Tab', contexts: ["link"] }) browser.contextMenus.create({ id: "redirectLinkInNewTab", title: "Redirect In New Tab", contexts: ["link"] })
browser.contextMenus.create({ id: "reverseLink", title: 'Redirect To Original', contexts: ["link"] }) browser.contextMenus.create({ id: "reverseLink", title: "Redirect To Original", contexts: ["link"] })
browser.contextMenus.create({ id: "reverseLinkInNewTab", title: 'Redirect To Original In New Tab', contexts: ["link"] }) browser.contextMenus.create({ id: "reverseLinkInNewTab", title: "Redirect To Original In New Tab", contexts: ["link"] })
browser.contextMenus.create({ id: "copyReverseLink", title: 'Copy Original', contexts: ["link"] }) browser.contextMenus.create({ id: "copyReverseLink", title: "Copy Original", contexts: ["link"] })
browser.contextMenus.create({ id: "bypassLink", title: 'Bypass', contexts: ["link"] }) browser.contextMenus.create({ id: "bypassLink", title: "Bypass", contexts: ["link"] })
browser.contextMenus.create({ id: "bypassLinkInNewTab", title: 'Bypass In New Tab', contexts: ["link"] }) browser.contextMenus.create({ id: "bypassLinkInNewTab", title: "Bypass In New Tab", contexts: ["link"] })
if (!isChrome) { if (!isChrome) {
browser.contextMenus.create({ id: "redirectBookmark", title: 'Redirect', contexts: ["bookmark"] }) browser.contextMenus.create({ id: "redirectBookmark", title: "Redirect", contexts: ["bookmark"] })
browser.contextMenus.create({ id: "redirectBookmarkInNewTab", title: 'Redirect In New Tab', contexts: ["bookmark"] }) browser.contextMenus.create({ id: "redirectBookmarkInNewTab", title: "Redirect In New Tab", contexts: ["bookmark"] })
browser.contextMenus.create({ id: "reverseBookmark", title: 'Redirect To Original', contexts: ["bookmark"] }) browser.contextMenus.create({ id: "reverseBookmark", title: "Redirect To Original", contexts: ["bookmark"] })
browser.contextMenus.create({ id: "reverseBookmarkInNewTab", title: 'Redirect To Original In New Tab', contexts: ["bookmark"] }) browser.contextMenus.create({
browser.contextMenus.create({ id: "copyReverseBookmark", title: 'Copy Original', contexts: ["bookmark"] }) id: "reverseBookmarkInNewTab",
browser.contextMenus.create({ id: "bypassBookmark", title: 'Bypass', contexts: ["bookmark"] }) title: "Redirect To Original In New Tab",
browser.contextMenus.create({ id: "bypassBookmarkInNewTab", title: 'Bypass In New Tab', contexts: ["bookmark"] }) contexts: ["bookmark"],
})
browser.contextMenus.create({ id: "copyReverseBookmark", title: "Copy Original", contexts: ["bookmark"] })
browser.contextMenus.create({ id: "bypassBookmark", title: "Bypass", contexts: ["bookmark"] })
browser.contextMenus.create({ id: "bypassBookmarkInNewTab", title: "Bypass In New Tab", contexts: ["bookmark"] })
} }
browser.contextMenus.onClicked.addListener(async (info) => { browser.contextMenus.onClicked.addListener(async info => {
switch (info.menuItemId) { switch (info.menuItemId) {
case 'switchInstanceTab': { case "switchInstanceTab": {
const url = new URL(info.pageUrl) const url = new URL(info.pageUrl)
const newUrl = await servicesHelper.switchInstance(url) const newUrl = await servicesHelper.switchInstance(url)
if (newUrl) browser.tabs.update({ url: newUrl }) if (newUrl) browser.tabs.update({ url: newUrl })
return return
} }
case 'settingsTab': case "settingsTab":
browser.runtime.openOptionsPage() browser.runtime.openOptionsPage()
return return
case 'copyReverseTab': case "copyReverseTab":
browser.tabs.query({ active: true, currentWindow: true }, async tabs => { browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) { if (tabs[0].url) {
const url = new URL(tabs[0].url) const url = new URL(tabs[0].url)
@ -173,7 +188,7 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
}) })
return return
case 'reverseTab': case "reverseTab":
browser.tabs.query({ active: true, currentWindow: true }, async tabs => { browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) { if (tabs[0].url) {
const url = new URL(tabs[0].url) const url = new URL(tabs[0].url)
@ -186,7 +201,7 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
}) })
return return
case 'redirectTab': case "redirectTab":
browser.tabs.query({ active: true, currentWindow: true }, async tabs => { browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) { if (tabs[0].url) {
const url = new URL(tabs[0].url) const url = new URL(tabs[0].url)
@ -199,13 +214,13 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
}) })
return return
case 'copyReverseLink': { case "copyReverseLink": {
const url = new URL(info.linkUrl) const url = new URL(info.linkUrl)
await servicesHelper.copyRaw(url) await servicesHelper.copyRaw(url)
return return
} }
case 'redirectLink': case "redirectLink":
case 'redirectLinkInNewTab': { case "redirectLinkInNewTab": {
const url = new URL(info.linkUrl) const url = new URL(info.linkUrl)
const newUrl = servicesHelper.redirect(url, "main_frame", null, true) const newUrl = servicesHelper.redirect(url, "main_frame", null, true)
if (newUrl) { if (newUrl) {
@ -214,8 +229,8 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
return return
} }
case 'reverseLink': case "reverseLink":
case 'reverseLinkInNewTab': { case "reverseLinkInNewTab": {
const url = new URL(info.linkUrl) const url = new URL(info.linkUrl)
const newUrl = await servicesHelper.reverse(url) const newUrl = await servicesHelper.reverse(url)
if (newUrl) { if (newUrl) {
@ -231,8 +246,8 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
return return
} }
case 'bypassLink': case "bypassLink":
case 'bypassLinkInNewTab': { case "bypassLinkInNewTab": {
const url = new URL(info.linkUrl) const url = new URL(info.linkUrl)
if (info.menuItemId == "bypassLink") { if (info.menuItemId == "bypassLink") {
browser.tabs.update({ url: url.href }, tab => { browser.tabs.update({ url: url.href }, tab => {
@ -245,25 +260,25 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
return return
} }
case 'copyReverseBookmark': case "copyReverseBookmark":
browser.bookmarks.get(info.bookmarkId, bookmarks => { browser.bookmarks.get(info.bookmarkId, bookmarks => {
const url = new URL(bookmarks[0].url) const url = new URL(bookmarks[0].url)
servicesHelper.copyRaw(url) servicesHelper.copyRaw(url)
}); })
return return
case 'redirectBookmark': case "redirectBookmark":
case 'redirectBookmarkInNewTab': case "redirectBookmarkInNewTab":
browser.bookmarks.get(info.bookmarkId, bookmarks => { browser.bookmarks.get(info.bookmarkId, bookmarks => {
const url = new URL(bookmarks[0].url) const url = new URL(bookmarks[0].url)
const newUrl = servicesHelper.redirect(url, "main_frame", null, true) const newUrl = servicesHelper.redirect(url, "main_frame", null, true)
if (newUrl) { if (newUrl) {
if (info.menuItemId == 'redirectBookmark') browser.tabs.update({ url: newUrl }) if (info.menuItemId == "redirectBookmark") browser.tabs.update({ url: newUrl })
else browser.tabs.create({ url: newUrl }) else browser.tabs.create({ url: newUrl })
} }
}) })
return return
case 'reverseBookmark': case "reverseBookmark":
case 'reverseBookmarkInNewTab': case "reverseBookmarkInNewTab":
browser.bookmarks.get(info.bookmarkId, async bookmarks => { browser.bookmarks.get(info.bookmarkId, async bookmarks => {
const url = new URL(bookmarks[0].url) const url = new URL(bookmarks[0].url)
const newUrl = await servicesHelper.reverse(url) const newUrl = await servicesHelper.reverse(url)
@ -280,14 +295,14 @@ browser.contextMenus.onClicked.addListener(async (info) => {
} }
}) })
return return
case 'bypassBookmark': case "bypassBookmark":
case 'bypassBookmarkInNewTab': case "bypassBookmarkInNewTab":
browser.bookmarks.get(info.bookmarkId, async bookmarks => { browser.bookmarks.get(info.bookmarkId, async bookmarks => {
const url = new URL(bookmarks[0].url) const url = new URL(bookmarks[0].url)
if (info.menuItemId == "bypassBookmark") { if (info.menuItemId == "bypassBookmark") {
browser.tabs.update({ url: url.href }, tab => tabIdRedirects[tab.id] = false) browser.tabs.update({ url: url.href }, tab => (tabIdRedirects[tab.id] = false))
} else { } else {
browser.tabs.create({ url: url.href }, tab => tabIdRedirects[tab.id] = false) browser.tabs.create({ url: url.href }, tab => (tabIdRedirects[tab.id] = false))
} }
return return
}) })
@ -300,16 +315,15 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (tabs[0].url) { if (tabs[0].url) {
const url = new URL(tabs[0].url) const url = new URL(tabs[0].url)
const newUrl = await servicesHelper.reverse(url) const newUrl = await servicesHelper.reverse(url)
if (newUrl) browser.tabs.update(tabs[0].id, { url: newUrl }, () => tabIdRedirects[tabs[0].id] = false) if (newUrl) browser.tabs.update(tabs[0].id, { url: newUrl }, () => (tabIdRedirects[tabs[0].id] = false))
} }
}) })
} } else if (request == "redirectTab") {
else if (request == "redirectTab") {
browser.tabs.query({ active: true, currentWindow: true }, async tabs => { browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) { if (tabs[0].url) {
const url = new URL(tabs[0].url) const url = new URL(tabs[0].url)
const newUrl = servicesHelper.redirect(url, "main_frame", null, true) const newUrl = servicesHelper.redirect(url, "main_frame", null, true)
if (newUrl) browser.tabs.update(tabs[0].id, { url: newUrl }, () => tabIdRedirects[tabs[0].id] = true) if (newUrl) browser.tabs.update(tabs[0].id, { url: newUrl }, () => (tabIdRedirects[tabs[0].id] = true))
} }
}) })
} }

View File

@ -1,11 +1,10 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<head> <meta charset="UTF-8" />
<meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="../stylesheets/styles.css" rel="stylesheet" />
<link href="../stylesheets/styles.css" rel="stylesheet">
<title>No instances found</title> <title>No instances found</title>
<style> <style>
#body { #body {
@ -15,12 +14,11 @@
height: 100vh; height: 100vh;
} }
</style> </style>
</head> </head>
<body> <body>
<div id="body"> <div id="body">
<h1>You have no instance selected for this frontend</h1> <h1>You have no instance selected for this frontend</h1>
</div> </div>
</body> </body>
</html> </html>

View File

@ -26,22 +26,23 @@ async function changeFrontendsSettings(service) {
options = await utils.getOptions() options = await utils.getOptions()
const opacityDiv = document.getElementById(`${service}-opacity`) const opacityDiv = document.getElementById(`${service}-opacity`)
if (document.getElementById(`${service}-enabled`).checked) { if (document.getElementById(`${service}-enabled`).checked) {
opacityDiv.style.pointerEvents = 'auto' opacityDiv.style.pointerEvents = "auto"
opacityDiv.style.opacity = 1 opacityDiv.style.opacity = 1
opacityDiv.style.userSelect = 'auto' opacityDiv.style.userSelect = "auto"
} else { } else {
opacityDiv.style.pointerEvents = 'none' opacityDiv.style.pointerEvents = "none"
opacityDiv.style.opacity = 0.4 opacityDiv.style.opacity = 0.4
opacityDiv.style.userSelect = 'none' opacityDiv.style.userSelect = "none"
} }
for (const frontend in config.services[service].frontends) { for (const frontend in config.services[service].frontends) {
if (config.services[service].frontends[frontend].instanceList) { if (config.services[service].frontends[frontend].instanceList) {
const frontendDiv = document.getElementById(frontend) const frontendDiv = document.getElementById(frontend)
if (typeof divs[service].frontend !== "undefined") { if (typeof divs[service].frontend !== "undefined") {
if ( if (
frontend == divs[service].frontend.value frontend == divs[service].frontend.value ||
|| (config.services[service].frontends[divs[service].frontend.value].desktopApp &&
(config.services[service].frontends[divs[service].frontend.value].desktopApp && divs[service].embedFrontend && frontend == divs[service].embedFrontend.value) divs[service].embedFrontend &&
frontend == divs[service].embedFrontend.value)
) { ) {
frontendDiv.style.display = "" frontendDiv.style.display = ""
if (config.services[service].frontends[frontend].localhost === true) { if (config.services[service].frontends[frontend].localhost === true) {
@ -67,8 +68,10 @@ async function changeFrontendsSettings(service) {
<option value="sub_frame" data-localise="__MSG_onlyEmbedded__">Only Embedded</option> <option value="sub_frame" data-localise="__MSG_onlyEmbedded__">Only Embedded</option>
<option value="main_frame" data-localise="__MSG_onlyNotEmbedded__">Only Not Embedded</option> <option value="main_frame" data-localise="__MSG_onlyNotEmbedded__">Only Not Embedded</option>
` `
} } else if (
else if (config.services[service].frontends[frontend].desktopApp && Object.values(config.services[service].frontends).some(frontend => frontend.embeddable)) { config.services[service].frontends[frontend].desktopApp &&
Object.values(config.services[service].frontends).some(frontend => frontend.embeddable)
) {
document.getElementById(`${service}-redirectType`).innerHTML = ` document.getElementById(`${service}-redirectType`).innerHTML = `
<option value="both" data-localise="__MSG_both__">both</options> <option value="both" data-localise="__MSG_both__">both</options>
<option value="main_frame" data-localise="__MSG_onlyNotEmbedded__">Only Not Embedded</option> <option value="main_frame" data-localise="__MSG_onlyNotEmbedded__">Only Not Embedded</option>
@ -86,14 +89,16 @@ async function changeFrontendsSettings(service) {
} }
document.getElementById(`${service}-redirectType`).value = options[service].redirectType document.getElementById(`${service}-redirectType`).value = options[service].redirectType
if (config.services[service].frontends[frontend].desktopApp && options[service].redirectType != "main_frame") { if (config.services[service].frontends[frontend].desktopApp && options[service].redirectType != "main_frame") {
document.getElementById(`${service}-embedFrontend-div`).style.display = '' document.getElementById(`${service}-embedFrontend-div`).style.display = ""
document.getElementById(divs[service].embedFrontend.value).style.display = '' document.getElementById(divs[service].embedFrontend.value).style.display = ""
} } else if (
else if (config.services[service].frontends[frontend].desktopApp && options[service].redirectType == "main_frame") { config.services[service].frontends[frontend].desktopApp &&
document.getElementById(`${service}-embedFrontend-div`).style.display = 'none' options[service].redirectType == "main_frame"
document.getElementById(divs[service].embedFrontend.value).style.display = 'none' ) {
document.getElementById(`${service}-embedFrontend-div`).style.display = "none"
document.getElementById(divs[service].embedFrontend.value).style.display = "none"
} else { } else {
document.getElementById(`${service}-embedFrontend-div`).style.display = 'none' document.getElementById(`${service}-embedFrontend-div`).style.display = "none"
} }
} }
const frontend_name_element = document.getElementById(`${service}_page`).getElementsByClassName("frontend_name")[0] const frontend_name_element = document.getElementById(`${service}_page`).getElementsByClassName("frontend_name")[0]
@ -109,7 +114,7 @@ async function loadPage(path) {
document.getElementById(`${path}_page`).style.display = "block" document.getElementById(`${path}_page`).style.display = "block"
for (const element of document.getElementsByClassName("title")) { for (const element of document.getElementsByClassName("title")) {
const a = element.getElementsByTagName('a')[0] const a = element.getElementsByTagName("a")[0]
if (a.getAttribute("href") == `#${path}`) { if (a.getAttribute("href") == `#${path}`) {
element.classList.add("selected") element.classList.add("selected")
} else { } else {
@ -127,19 +132,19 @@ async function loadPage(path) {
window.history.pushState({ id: "100" }, "Page 2", `/pages/options/index.html#${path}`) window.history.pushState({ id: "100" }, "Page 2", `/pages/options/index.html#${path}`)
if (path != 'general') { if (path != "general") {
const service = path; const service = path
divs[service] = {} divs[service] = {}
for (const option in config.services[service].options) { for (const option in config.services[service].options) {
divs[service][option] = document.getElementById(`${service}-${option}`) divs[service][option] = document.getElementById(`${service}-${option}`)
if (typeof config.services[service].options[option] == "boolean") divs[service][option].checked = options[service][option] if (typeof config.services[service].options[option] == "boolean")
divs[service][option].checked = options[service][option]
else divs[service][option].value = options[service][option] else divs[service][option].value = options[service][option]
divs[service][option].addEventListener("change", async () => { divs[service][option].addEventListener("change", async () => {
let options = await utils.getOptions() let options = await utils.getOptions()
if (typeof config.services[service].options[option] == "boolean") if (typeof config.services[service].options[option] == "boolean")
options[service][option] = divs[service][option].checked options[service][option] = divs[service][option].checked
else else options[service][option] = divs[service][option].value
options[service][option] = divs[service][option].value
browser.storage.local.set({ options }) browser.storage.local.set({ options })
changeFrontendsSettings(service) changeFrontendsSettings(service)
}) })
@ -150,18 +155,16 @@ async function loadPage(path) {
redirects = await utils.getList(options) redirects = await utils.getList(options)
for (const frontend in config.services[service].frontends) { for (const frontend in config.services[service].frontends) {
if (config.services[service].frontends[frontend].instanceList) { if (config.services[service].frontends[frontend].instanceList) {
if (redirects == 'disabled' || blacklist == 'disabled') { if (redirects == "disabled" || blacklist == "disabled") {
document.getElementById(frontend).getElementsByClassName('clearnet')[0].style.display = 'none' document.getElementById(frontend).getElementsByClassName("clearnet")[0].style.display = "none"
document.getElementById(frontend).getElementsByClassName('ping')[0].style.display = 'none' document.getElementById(frontend).getElementsByClassName("ping")[0].style.display = "none"
} } else if (!redirects || !blacklist) {
else if (!redirects || !blacklist) { document
document.getElementById(frontend) .getElementById(frontend)
.getElementsByClassName('clearnet')[0] .getElementsByClassName("clearnet")[0]
.getElementsByClassName("checklist")[0] .getElementsByClassName("checklist")[0]
.getElementsByClassName('loading')[0] .getElementsByClassName("loading")[0].innerHTML = "Could not fetch instances."
.innerHTML = 'Could not fetch instances.' } else {
}
else {
createList(frontend) createList(frontend)
} }
} }
@ -171,9 +174,9 @@ async function loadPage(path) {
if (config.services[service].frontends[frontend].instanceList) { if (config.services[service].frontends[frontend].instanceList) {
processCustomInstances(frontend) processCustomInstances(frontend)
document.getElementById(`ping-${frontend}`).addEventListener("click", async () => { document.getElementById(`ping-${frontend}`).addEventListener("click", async () => {
document.getElementById(`ping-${frontend}`).getElementsByTagName('x')[0].innerHTML = "Pinging..." document.getElementById(`ping-${frontend}`).getElementsByTagName("x")[0].innerHTML = "Pinging..."
await ping(frontend) await ping(frontend)
document.getElementById(`ping-${frontend}`).getElementsByTagName('x')[0].innerHTML = "Ping instances" document.getElementById(`ping-${frontend}`).getElementsByTagName("x")[0].innerHTML = "Ping instances"
}) })
} }
} }
@ -186,15 +189,12 @@ async function calcCustomInstances(frontend) {
const pingCache = await utils.getPingCache() const pingCache = await utils.getPingCache()
document.getElementById(frontend).getElementsByClassName("custom-checklist")[0].innerHTML = customInstances document.getElementById(frontend).getElementsByClassName("custom-checklist")[0].innerHTML = customInstances
.map( .map(x => {
x => { const time = pingCache[x]
const time = pingCache[x];
if (time) { if (time) {
var { color, text } = processTime(time); var { color, text } = processTime(time)
} }
const timeText = time const timeText = time ? `<span class="ping" style="color:${color};">${text}</span>` : ""
? `<span class="ping" style="color:${color};">${text}</span>`
: "";
const custom = isCustomInstance(frontend, x) ? "" : `<span>custom</span>` const custom = isCustomInstance(frontend, x) ? "" : `<span>custom</span>`
return `<div> return `<div>
<x> <x>
@ -212,7 +212,10 @@ async function calcCustomInstances(frontend) {
}) })
.join("\n") .join("\n")
for (const item of customInstances) { for (const item of customInstances) {
document.getElementById(frontend).getElementsByClassName(`clear-${item}`)[0].addEventListener("click", async () => { document
.getElementById(frontend)
.getElementsByClassName(`clear-${item}`)[0]
.addEventListener("click", async () => {
const index = customInstances.indexOf(item) const index = customInstances.indexOf(item)
if (index > -1) customInstances.splice(index, 1) if (index > -1) customInstances.splice(index, 1)
options = await utils.getOptions() options = await utils.getOptions()
@ -227,7 +230,10 @@ async function calcCustomInstances(frontend) {
async function processCustomInstances(frontend) { async function processCustomInstances(frontend) {
calcCustomInstances(frontend) calcCustomInstances(frontend)
document.getElementById(frontend).getElementsByClassName("custom-instance-form")[0].addEventListener("submit", async event => { document
.getElementById(frontend)
.getElementsByClassName("custom-instance-form")[0]
.addEventListener("submit", async event => {
event.preventDefault() event.preventDefault()
let options = await utils.getOptions() let options = await utils.getOptions()
let customInstances = options[frontend] let customInstances = options[frontend]
@ -259,7 +265,10 @@ async function createList(frontend) {
const pingCache = await utils.getPingCache() const pingCache = await utils.getPingCache()
const options = await utils.getOptions() const options = await utils.getOptions()
for (const network in config.networks) { for (const network in config.networks) {
const checklist = document.getElementById(frontend).getElementsByClassName(network)[0].getElementsByClassName("checklist")[0] const checklist = document
.getElementById(frontend)
.getElementsByClassName(network)[0]
.getElementsByClassName("checklist")[0]
if (!redirects[frontend]) { if (!redirects[frontend]) {
checklist.innerHTML = '<div class="block block-option">No instances found.</div>' checklist.innerHTML = '<div class="block block-option">No instances found.</div>'
@ -269,15 +278,16 @@ async function createList(frontend) {
const instances = redirects[frontend][network] const instances = redirects[frontend][network]
if (!instances || instances.length === 0) continue if (!instances || instances.length === 0) continue
document.getElementById(frontend).getElementsByClassName("custom-instance")[0].placeholder = redirects[frontend].clearnet[0] document.getElementById(frontend).getElementsByClassName("custom-instance")[0].placeholder =
redirects[frontend].clearnet[0]
instances.sort((a, b) => blacklist.cloudflare.includes(a) && !blacklist.cloudflare.includes(b)) instances.sort((a, b) => blacklist.cloudflare.includes(a) && !blacklist.cloudflare.includes(b))
const content = instances const content = instances.map(x => {
.map(x => { const cloudflare = blacklist.cloudflare.includes(x)
const cloudflare = blacklist.cloudflare.includes(x) ? ? `<a target="_blank" href="https://libredirect.github.io/docs.html#instances">
`<a target="_blank" href="https://libredirect.github.io/docs.html#instances">
<span style="color:red;">cloudflare</span> <span style="color:red;">cloudflare</span>
</a>` : "" </a>`
: ""
let time = pingCache[x] let time = pingCache[x]
let timeText = "" let timeText = ""
@ -307,12 +317,11 @@ async function createList(frontend) {
<label>${utils.camelCase(network)}</label> <label>${utils.camelCase(network)}</label>
</div>`, </div>`,
...content, ...content,
"<br>" "<br>",
].join("\n<hr>\n") ].join("\n<hr>\n")
for (const instance of instances) { for (const instance of instances) {
checklist.getElementsByClassName(`add-${instance}`)[0] checklist.getElementsByClassName(`add-${instance}`)[0].addEventListener("click", async () => {
.addEventListener("click", async () => {
let options = await utils.getOptions() let options = await utils.getOptions()
if (!options[frontend].includes(instance)) { if (!options[frontend].includes(instance)) {
options[frontend].push(instance) options[frontend].push(instance)
@ -335,21 +344,21 @@ else loadPage("general")
*/ */
async function ping(frontend) { async function ping(frontend) {
const instanceElements = [ const instanceElements = [
...document.getElementById(frontend).getElementsByClassName("custom-checklist")[0].getElementsByTagName('x'), ...document.getElementById(frontend).getElementsByClassName("custom-checklist")[0].getElementsByTagName("x"),
...document.getElementById(frontend).getElementsByClassName('clearnet')[0].getElementsByTagName('x') ...document.getElementById(frontend).getElementsByClassName("clearnet")[0].getElementsByTagName("x"),
] ]
let pingCache = await utils.getPingCache() let pingCache = await utils.getPingCache()
let redundancyList = {} let redundancyList = {}
for (const element of instanceElements) { for (const element of instanceElements) {
let span = element.getElementsByClassName('ping')[0] let span = element.getElementsByClassName("ping")[0]
if (!span) span = document.createElement('span') if (!span) span = document.createElement("span")
span.classList = ['ping'] span.classList = ["ping"]
span.innerHTML = '<span style="color:lightblue">pinging...</span>' span.innerHTML = '<span style="color:lightblue">pinging...</span>'
element.appendChild(span) element.appendChild(span)
const href = element.getElementsByTagName('a')[0].href const href = element.getElementsByTagName("a")[0].href
const innerHTML = element.getElementsByTagName('a')[0].innerHTML const innerHTML = element.getElementsByTagName("a")[0].innerHTML
const time = redundancyList[innerHTML] ?? await utils.ping(href) const time = redundancyList[innerHTML] ?? (await utils.ping(href))
const { color, text } = processTime(time) const { color, text } = processTime(time)
span.innerHTML = `<span style="color:${color};">${text}</span>` span.innerHTML = `<span style="color:${color};">${text}</span>`
pingCache[innerHTML] = time pingCache[innerHTML] = time
@ -369,22 +378,20 @@ function processTime(time) {
text = `${time}ms` text = `${time}ms`
if (time <= 1000) color = "green" if (time <= 1000) color = "green"
else if (time <= 2000) color = "orange" else if (time <= 2000) color = "orange"
} } else if (time >= 5000) {
else if (time >= 5000) {
color = "red" color = "red"
if (time == 5000) text = "5000ms+" if (time == 5000) text = "5000ms+"
if (time > 5000) text = `Error: ${time - 5000}` if (time > 5000) text = `Error: ${time - 5000}`
} } else {
else {
color = "red" color = "red"
text = 'Server not found' text = "Server not found"
} }
return { color, text } return { color, text }
} }
function isCustomInstance(frontend, instance) { function isCustomInstance(frontend, instance) {
for (const network in config.networks) { for (const network in config.networks) {
if (!redirects[frontend]) return false; if (!redirects[frontend]) return false
const instances = redirects[frontend][network] const instances = redirects[frontend][network]
if (instances.includes(instance)) return true if (instances.includes(instance)) return true
} }

View File

@ -13,29 +13,29 @@ async function changeTheme() {
case "dark": case "dark":
document.body.classList.add("dark-theme") document.body.classList.add("dark-theme")
document.body.classList.remove("light-theme") document.body.classList.remove("light-theme")
for (const element of document.body.getElementsByClassName('dark')) { for (const element of document.body.getElementsByClassName("dark")) {
element.style.display = 'none'; element.style.display = "none"
} }
break break
case "light": case "light":
document.body.classList.add("light-theme") document.body.classList.add("light-theme")
document.body.classList.remove("dark-theme") document.body.classList.remove("dark-theme")
for (const element of document.body.getElementsByClassName('light')) { for (const element of document.body.getElementsByClassName("light")) {
element.style.display = 'none'; element.style.display = "none"
} }
break break
default: default:
if (matchMedia("(prefers-color-scheme: light)").matches) { if (matchMedia("(prefers-color-scheme: light)").matches) {
document.body.classList.add("light-theme") document.body.classList.add("light-theme")
document.body.classList.remove("dark-theme") document.body.classList.remove("dark-theme")
for (const element of document.body.getElementsByClassName('light')) { for (const element of document.body.getElementsByClassName("light")) {
element.style.display = 'none'; element.style.display = "none"
} }
} else { } else {
document.body.classList.add("dark-theme") document.body.classList.add("dark-theme")
document.body.classList.remove("light-theme") document.body.classList.remove("light-theme")
for (const element of document.body.getElementsByClassName('dark')) { for (const element of document.body.getElementsByClassName("dark")) {
element.style.display = 'none'; element.style.display = "none"
} }
} }
} }

View File

@ -11,13 +11,13 @@ async function setOption(option, type, event) {
switch (type) { switch (type) {
case "select": case "select":
options[option] = event.target.options[event.target.options.selectedIndex].value options[option] = event.target.options[event.target.options.selectedIndex].value
break; break
case "checkbox": case "checkbox":
options[option] = event.target.checked options[option] = event.target.checked
break; break
case "range": case "range":
options[option] = event.target.value options[option] = event.target.value
break; break
} }
browser.storage.local.set({ options }) browser.storage.local.set({ options })
} }
@ -48,10 +48,7 @@ importSettingsElement.addEventListener("change", () => {
reader.readAsText(file) reader.readAsText(file)
reader.onload = async () => { reader.onload = async () => {
const data = JSON.parse(reader.result) const data = JSON.parse(reader.result)
if ( if ("theme" in data && data.version == browser.runtime.getManifest().version) {
"theme" in data
&& data.version == browser.runtime.getManifest().version
) {
browser.storage.local.clear(async () => { browser.storage.local.clear(async () => {
browser.storage.local.set({ options: data }, () => { browser.storage.local.set({ options: data }, () => {
location.reload() location.reload()
@ -102,23 +99,22 @@ resetSettings.addEventListener("click", async () => {
location.reload() location.reload()
}) })
const fetchInstancesElement = document.getElementById('fetch-instances') const fetchInstancesElement = document.getElementById("fetch-instances")
fetchInstancesElement.addEventListener('change', event => { fetchInstancesElement.addEventListener("change", event => {
setOption('fetchInstances', 'select', event) setOption("fetchInstances", "select", event)
location.reload() location.reload()
}) })
const redirectOnlyInIncognitoElement = document.getElementById('redirectOnlyInIncognito') const redirectOnlyInIncognitoElement = document.getElementById("redirectOnlyInIncognito")
redirectOnlyInIncognitoElement.addEventListener('change', event => { redirectOnlyInIncognitoElement.addEventListener("change", event => {
setOption('redirectOnlyInIncognito', 'checkbox', event) setOption("redirectOnlyInIncognito", "checkbox", event)
}) })
const bookmarksMenuElement = document.getElementById('bookmarksMenu') const bookmarksMenuElement = document.getElementById("bookmarksMenu")
bookmarksMenuElement.addEventListener('change', async event => { bookmarksMenuElement.addEventListener("change", async event => {
if (event.target.checked) if (event.target.checked)
browser.permissions.request({ permissions: ["bookmarks"] }, r => bookmarksMenuElement.checked = r) browser.permissions.request({ permissions: ["bookmarks"] }, r => (bookmarksMenuElement.checked = r))
else else browser.permissions.remove({ permissions: ["bookmarks"] }, r => (bookmarksMenuElement.checked = !r))
browser.permissions.remove({ permissions: ["bookmarks"] }, r => bookmarksMenuElement.checked = !r)
}) })
let themeElement = document.getElementById("theme") let themeElement = document.getElementById("theme")
@ -149,8 +145,9 @@ let options = await utils.getOptions()
themeElement.value = options.theme themeElement.value = options.theme
fetchInstancesElement.value = options.fetchInstances fetchInstancesElement.value = options.fetchInstances
redirectOnlyInIncognitoElement.checked = options.redirectOnlyInIncognito redirectOnlyInIncognitoElement.checked = options.redirectOnlyInIncognito
browser.permissions.contains({ permissions: ["bookmarks"] }, r => bookmarksMenuElement.checked = r) browser.permissions.contains({ permissions: ["bookmarks"] }, r => (bookmarksMenuElement.checked = r))
for (const service in config.services) document.getElementById(service).checked = options.popupServices.includes(service) for (const service in config.services)
document.getElementById(service).checked = options.popupServices.includes(service)
instanceTypeElement.addEventListener("change", event => { instanceTypeElement.addEventListener("change", event => {
instanceType = event.target.options[instanceTypeElement.selectedIndex].value instanceType = event.target.options[instanceTypeElement.selectedIndex].value
@ -165,7 +162,10 @@ instanceTypeElement.addEventListener("change", event => {
let exceptionsCustomInstances = options.exceptions let exceptionsCustomInstances = options.exceptions
function calcExceptionsCustomInstances() { function calcExceptionsCustomInstances() {
document.getElementById("exceptions-custom-checklist").innerHTML = [...exceptionsCustomInstances.url, ...exceptionsCustomInstances.regex] document.getElementById("exceptions-custom-checklist").innerHTML = [
...exceptionsCustomInstances.url,
...exceptionsCustomInstances.regex,
]
.map( .map(
x => `<div> x => `<div>
${x} ${x}
@ -210,7 +210,7 @@ document.getElementById("custom-exceptions-instance-form").addEventListener("sub
if (val) { if (val) {
options = await utils.getOptions() options = await utils.getOptions()
options.exceptions = exceptionsCustomInstances options.exceptions = exceptionsCustomInstances
browser.storage.local.set({ options }, () => nameCustomInstanceInput.value = "") browser.storage.local.set({ options }, () => (nameCustomInstanceInput.value = ""))
} }
calcExceptionsCustomInstances() calcExceptionsCustomInstances()
}) })

View File

@ -5,7 +5,7 @@ import servicesHelper from "../../assets/javascripts/services.js"
import utils from "../../assets/javascripts/utils.js" import utils from "../../assets/javascripts/utils.js"
document.getElementById("more-options").href = browser.runtime.getURL("pages/options/index.html") document.getElementById("more-options").href = browser.runtime.getURL("pages/options/index.html")
document.getElementById("more-options").setAttribute('target', '_blank') document.getElementById("more-options").setAttribute("target", "_blank")
await browser.runtime.getPlatformInfo(r => { await browser.runtime.getPlatformInfo(r => {
switch (r.os) { switch (r.os) {
@ -71,9 +71,9 @@ browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (r) { if (r) {
document.getElementById("change_instance_div").style.display = "" document.getElementById("change_instance_div").style.display = ""
hr.style.display = "" hr.style.display = ""
document.getElementById("change_instance").addEventListener("click", async () => document
browser.tabs.update({ url: await servicesHelper.switchInstance(url) }) .getElementById("change_instance")
) .addEventListener("click", async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url) }))
} }
}) })
servicesHelper.reverse(url).then(r => { servicesHelper.reverse(url).then(r => {
@ -84,7 +84,9 @@ browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
document.getElementById("copy_original").addEventListener("click", () => servicesHelper.copyRaw(url)) document.getElementById("copy_original").addEventListener("click", () => servicesHelper.copyRaw(url))
document.getElementById("redirect_to_original_div").style.display = "" document.getElementById("redirect_to_original_div").style.display = ""
document.getElementById("redirect_to_original").addEventListener("click", () => browser.runtime.sendMessage("reverseTab")) document
.getElementById("redirect_to_original")
.addEventListener("click", () => browser.runtime.sendMessage("reverseTab"))
} }
}) })
servicesHelper.redirectAsync(url, "main_frame", null, true).then(r => { servicesHelper.redirectAsync(url, "main_frame", null, true).then(r => {

View File

@ -54,7 +54,7 @@ div.block input[type="checkbox"] {
text-decoration: none; text-decoration: none;
width: min-content; width: min-content;
color: var(--text); color: var(--text);
transition: .1s; transition: 0.1s;
} }
.title:hover { .title:hover {
@ -348,7 +348,7 @@ body.light-theme a {
} }
body.light-theme a:hover { body.light-theme a:hover {
color: var(--active) color: var(--active);
} }
button { button {
@ -438,7 +438,6 @@ html.mobile body.option {
align-items: center; align-items: center;
} }
html.mobile section.links { html.mobile section.links {
flex-direction: row; flex-direction: row;
width: 100%; width: 100%;

View File

@ -47,7 +47,7 @@ Bandcamp - [https://thorwegian.bandcamp.com/track/just-because](https://thorwegi
Instructables - [https://instructables.com/DIY-Arduino-Obstacle-Avoiding-Car-at-Home/](https://instructables.com/DIY-Arduino-Obstacle-Avoiding-Car-at-Home/) Instructables - [https://instructables.com/DIY-Arduino-Obstacle-Avoiding-Car-at-Home/](https://instructables.com/DIY-Arduino-Obstacle-Avoiding-Car-at-Home/)
Web archive - [https://web.archive.org/web/20230131222432if_/https://www.dailymail.co.uk/news/article-11687675/Army-spied-lockdown-critics-Sceptics-including-Peter-Hitchens-suspected-watched.html](https://web.archive.org/web/20230131222432if_/https://www.dailymail.co.uk/news/article-11687675/Army-spied-lockdown-critics-Sceptics-including-Peter-Hitchens-suspected-watched.html) Web archive - [https://web.archive.org/web/20230131222432if\_/https://www.dailymail.co.uk/news/article-11687675/Army-spied-lockdown-critics-Sceptics-including-Peter-Hitchens-suspected-watched.html](https://web.archive.org/web/20230131222432if_/https://www.dailymail.co.uk/news/article-11687675/Army-spied-lockdown-critics-Sceptics-including-Peter-Hitchens-suspected-watched.html)
--- ---