diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-01-29 17:19:04 +0100 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-01-29 17:19:04 +0100 |
commit | 0cfcd80f3a715a77821aa83e0c89245ec2f53eec (patch) | |
tree | aec2aea5c24c15f287bc05e695b60d45a26e6dc8 /src/assets/javascripts | |
parent | chore(merge): Merge remote-tracking branch 'origin/master' (diff) | |
parent | Added Structables, and made it the default https://codeberg.org/LibRedirect/b... (diff) | |
download | libredirect-0cfcd80f3a715a77821aa83e0c89245ec2f53eec.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src/assets/javascripts')
-rw-r--r-- | src/assets/javascripts/services.js | 188 | ||||
-rw-r--r-- | src/assets/javascripts/utils.js | 20 |
2 files changed, 165 insertions, 43 deletions
diff --git a/src/assets/javascripts/services.js b/src/assets/javascripts/services.js index 7213380f..961759c2 100644 --- a/src/assets/javascripts/services.js +++ b/src/assets/javascripts/services.js @@ -54,9 +54,10 @@ function regexArray(service, url, config, options, frontend) { * @param {URL} url * @param {string} frontend * @param {string} randomInstance + * @param {string} type * @returns {undefined|string} */ -function rewrite(url, originUrl, frontend, randomInstance) { +function rewrite(url, originUrl, frontend, randomInstance, type) { switch (frontend) { case "hyperpipe": for (const key of [...url.searchParams.keys()]) if (key !== "q") url.searchParams.delete(key) @@ -99,6 +100,7 @@ function rewrite(url, originUrl, frontend, randomInstance) { if (/\/@[a-z]+\//.exec(url.pathname)) return randomInstance return `${randomInstance}${url.pathname}${url.search}` } + case "small": case "libMedium": case "scribe": { const regex = url.hostname.match(/^(link|cdn-images-\d+|.*)\.medium\.com/) @@ -220,9 +222,9 @@ function rewrite(url, originUrl, frontend, randomInstance) { return `${randomInstance}${url.pathname}${url.search}` case "redlib": case "libreddit": { - const subdomain = url.hostname.match(/^(?:(?:external-)?preview|i)(?=\.redd\.it)/) + const subdomain = url.hostname.match(/^(?:((?:external-)?preview|i)\.)?redd\.it/) if (!subdomain) return `${randomInstance}${url.pathname}${url.search}` - switch (subdomain[0]) { + switch (subdomain[1]) { case "preview": return `${randomInstance}/preview/pre${url.pathname}${url.search}` case "external-preview": @@ -230,7 +232,7 @@ function rewrite(url, originUrl, frontend, randomInstance) { case "i": return `${randomInstance}/img${url.pathname}` } - return randomInstance + return `${randomInstance}/comments${url.pathname}` } case "teddit": if (/^(?:(?:external-)?preview|i)\.redd\.it/.test(url.hostname)) { @@ -238,6 +240,7 @@ function rewrite(url, originUrl, frontend, randomInstance) { else return `${randomInstance}${url.pathname}${url.search}&teddit_proxy=${url.hostname}` } return `${randomInstance}${url.pathname}${url.search}` + case "troddit": case "eddrit": if (/^(?:(?:external-)?preview|i)\.redd\.it/.test(url.hostname)) return randomInstance return `${randomInstance}${url.pathname}${url.search}` @@ -267,8 +270,11 @@ function rewrite(url, originUrl, frontend, randomInstance) { // https://stackexchange.com or https://superuser.com return `${randomInstance}${url.pathname}${url.search}` } - const regex = url.href.match(/https?:\/{2}(?:([a-zA-Z0-9-]+)\.)?stackexchange\.com\//) + const regex = url.href.match(/https?:\/{2}(?:([a-zA-Z0-9-]+)\.(meta\.)?)?stackexchange\.com\//) if (regex && regex.length > 1) { + if (regex[2]) { + return `${randomInstance}/exchange/${url.hostname}${url.pathname}${url.search}` + } const subdomain = regex[1] return `${randomInstance}/exchange/${subdomain}${url.pathname}${url.search}` } @@ -282,6 +288,15 @@ function rewrite(url, originUrl, frontend, randomInstance) { } case "biblioReads": return `${randomInstance}${url.pathname}${url.search}` + case "wikimore": { + let hostSplit = url.host.split(".") + // wikiless doesn't have mobile view support yet + if (hostSplit[0] != "wikipedia" && hostSplit[0] != "www") { + const lang = url.hostname.split(".")[0] + return `${randomInstance}/wiki/${lang}${url.pathname}${url.search}${url.hash}` + } + return `${randomInstance}${url.pathname}${url.search}${url.hash}` + } case "wikiless": { let hostSplit = url.host.split(".") // wikiless doesn't have mobile view support yet @@ -292,6 +307,7 @@ function rewrite(url, originUrl, frontend, randomInstance) { } return `${randomInstance}${url.pathname}${url.search}${url.hash}` } + case "offtiktok": case "proxiTok": if (url.pathname.startsWith("/email")) return randomInstance return `${randomInstance}${url.pathname}${url.search}` @@ -353,7 +369,10 @@ function rewrite(url, originUrl, frontend, randomInstance) { } } case "binternet": - if (url.hostname == "i.pinimg.com") return `${randomInstance}/image_proxy.php?url=${url.href}` + if (url.hostname == "i.pinimg.com") return `${randomInstance}/image_proxy.php?url=${encodeURIComponent(url.href)}` + return `${randomInstance}${url.pathname}${url.search}` + case "painterest": + if (url.hostname == "i.pinimg.com") return `${randomInstance}/_/proxy?url=${encodeURIComponent(url.href)}` return `${randomInstance}${url.pathname}${url.search}` case "laboratory": { let path = url.pathname @@ -378,11 +397,24 @@ function rewrite(url, originUrl, frontend, randomInstance) { } return `${randomInstance}${url.pathname}${url.search}` } + case "vixipy": { + const regex = /\/[a-z]{1,3}\/(.*)/.exec(url.pathname) + if (regex) { + let path = regex[1] + if (path.startsWith("tags/")) path = path.replace(/tags/, "tag") + return `${randomInstance}/${path}${url.search}` + } + return `${randomInstance}${url.pathname}${url.search}` + } case "invidious": { + // tracker url.searchParams.delete("si") + + if (type == "sub_frame") url.searchParams.append("autoplay", "0") + if (url.hostname == "youtu.be" || (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/live"))) { const watch = url.pathname.substring(url.pathname.lastIndexOf("/") + 1) - return `${randomInstance}/watch?v=${watch}${url.search.replace("?", "&")}` + return `${randomInstance}/watch?v=${watch}&${url.search.substring(1)}` } if (url.hostname.endsWith("youtube.com") && url.pathname.startsWith("/redirect?")) return url.href return `${randomInstance}${url.pathname}${url.search}` @@ -501,6 +533,7 @@ function rewrite(url, originUrl, frontend, randomInstance) { } return `${randomInstance}${url.pathname}${url.search}` } + case "ultimateTab": case "freetar": if (url.pathname.startsWith("/search.php")) { url.searchParams.set("search_term", url.searchParams.get("value")) @@ -519,16 +552,16 @@ function rewrite(url, originUrl, frontend, randomInstance) { return `${randomInstance}${url.pathname}${url.search}` } case "skunkyArt": { - if (url.pathname.startsWith("/search")) return `${randomInstance}${url.pathname}${url.search}&scope=all` + if (url.pathname.startsWith("/search")) return `${randomInstance}${url.pathname}${url.search}&type=all` - const artReg = /^\/.*?\/art\/(.*)\/?/.exec(url.pathname) - if (artReg) return `${randomInstance}/post/art/${artReg[1]}${url.search}` + const artReg = /^\/(.*?)\/art\/(.*)\/?/.exec(url.pathname) + if (artReg) return `${randomInstance}/post/${artReg[1]}/${artReg[2]}${url.search}` const userReg = /^\/([^\/]+)$/.exec(url.pathname) - if (userReg) return `${randomInstance}/user/${userReg[1]}${url.search}` + if (userReg) return `${randomInstance}/group_user?q=${userReg[1]}&type=about` - const galleryReg = /^\/.*?\/gallery(\/$|$)$/.exec(url.pathname) - if (galleryReg) return `${randomInstance}/user/${userReg[1]}?a=gallery` + const galleryReg = /^\/(.*?)\/gallery(\/$|$)$/.exec(url.pathname) + if (galleryReg) return `${randomInstance}/group_user?q=${galleryReg[1]}&type=gallery` return `${randomInstance}${url.pathname}${url.search}` } @@ -550,6 +583,43 @@ function rewrite(url, originUrl, frontend, randomInstance) { const accountReg = /^\/([^\/]+)\/?$/.exec(url.pathname) if (accountReg) return `${randomInstance}/account${url.pathname}${url.search}` + case "duckDuckGoAiChat": + return "https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=1" + + case "soundcloak": + if (url.pathname.startsWith("/feed") || url.pathname.startsWith("/stream")) { + // this feature requires authentication and is unsupported, so just redirect to main page + return randomInstance + } + + if (url.pathname.startsWith("/search")) { + if (!url.search) { + return randomInstance + } + + let type = "" + if (url.pathname.startsWith("/search/sounds")) { + type = "tracks" + } else if (url.pathname.startsWith("/search/people")) { + type = "users" + } else if (url.pathname.startsWith("/search/albums") || url.pathname.startsWith("/search/sets")) { + type = "playlists" + } + + if (type) { + type = "&type=" + type + } else { + return randomInstance // fallback for unsupported search types (searching for anything for example) + } + + return `${randomInstance}/search${url.search}${type}` + } + + if (url.host == "on.soundcloud.com") { + return `${randomInstance}/on${url.pathname}` + } + + return `${randomInstance}${url.pathname}${url.search}` case "piped": case "pipedMaterial": case "cloudtube": @@ -627,7 +697,7 @@ function redirect(url, type, originUrl, documentUrl, incognito, forceRedirection } if (!frontend) return - return rewrite(url, originUrl, frontend, randomInstance) + return rewrite(url, originUrl, frontend, randomInstance, type) } /** @@ -647,30 +717,19 @@ async function redirectAsync(url, type, originUrl, documentUrl, incognito, force /** * @param {URL} url */ -function computeService(url) { - return new Promise(async resolve => { - const config = await utils.getConfig() - const options = await utils.getOptions() - for (const service in config.services) { - if (regexArray(service, url, config, options)) { - resolve(service) - return - } else { - for (const frontend in config.services[service].frontends) { - if (all(service, frontend, options, config).findIndex(instance => url.href.startsWith(instance)) >= 0) { - return resolve(service) - } - } - } - } - resolve() - }) -} -export function computeFrontend(url) { +async function computeServiceFrontend(url) { + const config = await utils.getConfig() + const options = await utils.getOptions() for (const service in config.services) { - for (const frontend in config.services[service].frontends) { - if (all(service, frontend, options, config).findIndex(instance => url.href.startsWith(instance)) >= 0) { - return { service, frontend } + if (regexArray(service, url, config, options)) { + return { service, frontend: null } + } else { + for (const frontend in config.services[service].frontends) { + const instances = all(service, frontend, options, config) + const i = instances.findIndex(instance => url.href.startsWith(instance)) + if (i >= 0) { + return { service, frontend } + } } } } @@ -765,6 +824,39 @@ async function reverse(url) { return `${config.services[service].url}/${url.search.slice(1)}` case "goodreads": return `https://goodreads.com${url.pathname}${url.search}` + case "soundcloud": + if (frontend == "soundcloak") { + if (url.pathname.includes("/_/")) { + // soundcloak-specific pages + return `${config.services[service].url}${url.pathname.split("/_/")[0]}` + } + + if (url.pathname == "/search") { + let type = url.searchParams.get("type") + switch (type) { + case "playlists": + type = "sets" + break + case "tracks": + type = "sounds" + break + case "users": + type = "people" + break + default: + type = "" + } + + url.searchParams.delete("type") + if (!type) { + return `${config.services[service].url}/search?${url.searchParams.toString()}` + } else { + return `${config.services[service].url}/search/${type}?${url.searchParams.toString()}` + } + } + + return `${config.services[service].url}${url.pathname}` + } default: return } @@ -783,9 +875,12 @@ const defaultInstances = { poketube: ["https://poketube.fun"], proxiTok: ["https://proxitok.pabloferreiro.es"], redlib: ["https://libreddit.vhack.eu"], + offtiktok: ["https://www.offtiktok.com"], eddrit: ["https://eddrit.com"], + troddit: ["https://www.troddit.com"], scribe: ["https://scribe.rip"], libMedium: ["https://md.vern.cc"], + small: ["https://small.bloat.cat"], quetre: ["https://quetre.iket.me"], libremdb: ["https://libremdb.iket.me"], simplyTranslate: ["https://simplytranslate.org"], @@ -811,27 +906,36 @@ const defaultInstances = { wolfreeAlpha: ["https://gqq.gitlab.io", "https://uqq.gitlab.io"], laboratory: ["https://lab.vern.cc"], binternet: ["https://bn.bloat.cat"], + painterest: ["https://pt.bloat.cat"], pixivFe: ["https://pixivfe.exozy.me"], liteXiv: ["https://litexiv.exozy.me"], + vixipy: ["https://vx.maid.zone"], indestructables: ["https://indestructables.private.coffee"], destructables: ["https://ds.vern.cc"], + structables: ["https://structables.private.coffee"], safetwitch: ["https://safetwitch.drgns.space"], twineo: ["https://twineo.exozy.me"], proxigram: ["https://ig.opnxng.com"], - tuboYoutube: ["https://tubo.migalmoreno.com"], - tuboSoundcloud: ["https://tubo.migalmoreno.com"], + tuboYoutube: ["https://tubo.media"], + tuboSoundcloud: ["https://tubo.media"], tekstoLibre: ["https://davilarek.github.io/TekstoLibre"], skyview: ["https://skyview.social"], priviblur: ["https://pb.bloat.cat"], nitter: ["https://nitter.privacydev.net"], pasted: ["https://pasted.drakeerv.com"], + pasty: ["https://pasty.lus.pm"], freetar: ["https://freetar.de"], + ultimateTab: ["https://ultimate-tab.com"], ratAintTieba: ["https://rat.fis.land"], shoelace: ["https://shoelace.mint.lgbt"], skunkyArt: ["https://skunky.bloat.cat"], - ytify: ["https://ytify.netlify.app"], + ytify: ["https://ytify.us.kg"], nerdsForNerds: ["https://nn.vern.cc"], + ducksForDucks: ["https://ducksforducks.private.coffee"], koub: ["https://koub.clovius.club"], + soundcloak: ["https://soundcloak.fly.dev"], + gocook: ["https://cook.adminforge.de"], + wikimore: ["https://wikimore.private.coffee"], } async function getDefaults() { @@ -942,6 +1046,7 @@ async function copyRaw(url) { * @param {URL} url */ function isException(url) { + if (!options) return false if (!options.exceptions) return false let exceptions = options.exceptions if (exceptions && url) { @@ -968,12 +1073,11 @@ function isException(url) { export default { redirect, redirectAsync, - computeService, + computeServiceFrontend, reverse, initDefaults, processUpdate, copyRaw, switchInstance, isException, - computeFrontend, } diff --git a/src/assets/javascripts/utils.js b/src/assets/javascripts/utils.js index e5b8ba46..f360a15b 100644 --- a/src/assets/javascripts/utils.js +++ b/src/assets/javascripts/utils.js @@ -31,7 +31,8 @@ function protocolHost(url) { if (url.pathname == "/TekstoLibre/" && url.host.endsWith("github.io")) return `${url.protocol}//${url.host}${url.pathname.slice(0, -1)}` - return `${url.protocol}//${url.host}${url.pathname}` + const pathname = url.pathname != "/" ? url.pathname : "" + return `${url.protocol}//${url.host}${pathname}` } /** @@ -221,6 +222,22 @@ export function randomInstances(clearnet, n) { } return instances } + +async function autoPickInstance(clearnet, url) { + if (url) { + const i = clearnet.findIndex(instance => url.href.startsWith(instance)) + if (i >= 0) clearnet.splice(i, 1) + } + const random = randomInstances(clearnet, 5) + const pings = await Promise.all([ + ...random.map(async instance => { + return [instance, await ping(instance)] + }), + ]) + pings.sort((a, b) => a[1] - b[1]) + return pings[0][0] +} + export function style(options, window) { const vars = cssVariables(options, window) return `--text: ${vars.text}; @@ -276,4 +293,5 @@ export default { convertMapCentre, randomInstances, style, + autoPickInstance, } |