From d2f4f32b2586308e1122120bb4cf7d1646bcdd2b Mon Sep 17 00:00:00 2001 From: Hailey Date: Wed, 26 Jun 2024 16:52:03 -0700 Subject: [PATCH] resolve short links --- src/lib/link-meta/resolve-short-link.ts | 22 +++++++++++++++++ src/lib/strings/url-helpers.ts | 11 +++++++++ src/state/queries/useResolveShortLink.ts | 24 ------------------- src/view/com/composer/useExternalLinkFetch.ts | 13 ++++++++++ 4 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 src/lib/link-meta/resolve-short-link.ts delete mode 100644 src/state/queries/useResolveShortLink.ts diff --git a/src/lib/link-meta/resolve-short-link.ts b/src/lib/link-meta/resolve-short-link.ts new file mode 100644 index 0000000000..7625c20943 --- /dev/null +++ b/src/lib/link-meta/resolve-short-link.ts @@ -0,0 +1,22 @@ +import {logger} from '#/logger' + +export async function resolveShortLink(shortLink: string) { + const controller = new AbortController() + const to = setTimeout(() => controller.abort(), 2e3) + + try { + const res = await fetch(shortLink, { + method: 'GET', + signal: controller.signal, + }) + if (res.status !== 301) { + return res.url + } + return res.headers.get('Location') + } catch (e: unknown) { + logger.error('Failed to resolve short link', {safeMessage: e}) + return null + } finally { + clearTimeout(to) + } +} diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts index 4c75f47add..b88b77f735 100644 --- a/src/lib/strings/url-helpers.ts +++ b/src/lib/strings/url-helpers.ts @@ -2,6 +2,7 @@ import {AtUri} from '@atproto/api' import psl from 'psl' import TLDs from 'tlds' +import {logger} from '#/logger' import {BSKY_SERVICE} from 'lib/constants' import {isInvalidHandle} from 'lib/strings/handles' @@ -285,3 +286,13 @@ export function createBskyAppAbsoluteUrl(path: string): string { const sanitizedPath = path.replace(BSKY_APP_HOST, '').replace(/^\/+/, '') return `${BSKY_APP_HOST.replace(/\/$/, '')}/${sanitizedPath}` } + +export function isShortLink(url: string): boolean { + try { + const urlp = new URL(url) + return urlp.host === 'go.bsky.app' + } catch (e) { + logger.error('Failed to parse possible short link', {safeMessage: e}) + return false + } +} diff --git a/src/state/queries/useResolveShortLink.ts b/src/state/queries/useResolveShortLink.ts deleted file mode 100644 index ba781cab4e..0000000000 --- a/src/state/queries/useResolveShortLink.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {logger} from '#/logger' - -export function useResolveShortLink() { - return async (shortLink: string) => { - const controller = new AbortController() - const to = setTimeout(() => controller.abort(), 2e3) - - try { - const res = await fetch( - shortLink, - {method: 'HEAD', redirect: 'manual'}, - {signal: controller.signal}, - ) - if (res.status !== 301) { - return shortLink - } - return res.headers.get('Location') - } catch (e: unknown) { - logger.error('Failed to resolve short link', {safeMessage: e}) - } finally { - clearTimeout(to) - } - } -} diff --git a/src/view/com/composer/useExternalLinkFetch.ts b/src/view/com/composer/useExternalLinkFetch.ts index 2e0297a475..743535a5e0 100644 --- a/src/view/com/composer/useExternalLinkFetch.ts +++ b/src/view/com/composer/useExternalLinkFetch.ts @@ -12,11 +12,13 @@ import { getPostAsQuote, } from 'lib/link-meta/bsky' import {getLinkMeta} from 'lib/link-meta/link-meta' +import {resolveShortLink} from 'lib/link-meta/resolve-short-link' import {downloadAndResize} from 'lib/media/manip' import { isBskyCustomFeedUrl, isBskyListUrl, isBskyPostUrl, + isShortLink, } from 'lib/strings/url-helpers' import {ImageModel} from 'state/models/media/image' import {ComposerOpts} from 'state/shell/composer' @@ -94,6 +96,17 @@ export function useExternalLinkFetch({ setExtLink(undefined) }, ) + } else if (isShortLink(extLink.uri)) { + if (isShortLink(extLink.uri)) { + resolveShortLink(extLink.uri).then(res => { + if (res && res !== extLink.uri) { + setExtLink({ + uri: res, + isLoading: true, + }) + } + }) + } } else { getLinkMeta(agent, extLink.uri).then(meta => { if (aborted) {