Resolve a link content type per url rather than per event

This commit is contained in:
Coracle-Bot 2026-09-08 21:38:50 +00:00 committed by hodlbod
parent 8e46f5a15b
commit 1da59fb322
4 changed files with 39 additions and 20 deletions

View file

@ -16,7 +16,7 @@
<script lang="ts">
import {call, ellipsize, displayUrl} from "@welshman/lib"
import {isRelayUrl, tagSpec, tagValue} from "@welshman/util"
import {isRelayUrl} from "@welshman/util"
import {Capacitor} from "@capacitor/core"
import {preventDefault, stopPropagation} from "@lib/html"
import Link from "@lib/components/Link.svelte"
@ -26,7 +26,12 @@
import ContentLinkBlockImage from "@app/components/ContentLinkBlockImage.svelte"
import {pushModal} from "@app/modal"
import {PLATFORM_URL, THUMBNAIL_URL} from "@app/env"
import {AUDIO_CONTENT_TYPES, IMAGE_CONTENT_TYPES, VIDEO_CONTENT_TYPES} from "@app/content"
import {
getUrlContentType,
AUDIO_CONTENT_TYPES,
IMAGE_CONTENT_TYPES,
VIDEO_CONTENT_TYPES,
} from "@app/content"
import {isRoomId} from "@app/rooms"
const {value, event} = $props()
@ -41,7 +46,7 @@
return [url, true]
})
const fileType = tagValue(tagSpec("file-type"), event.tags) || ""
const fileType = getUrlContentType(url, event)
const isAudio =
Boolean(url.match(/\.(mp3|m4a|wav|ogg|oga|opus|flac)$/)) ||

View file

@ -1,26 +1,16 @@
<script lang="ts">
import {onMount, onDestroy} from "svelte"
import {displayUrl, once} from "@welshman/lib"
import {
getBlob,
decryptFile,
makeBlossomAuthEvent,
matchTags,
tagSpec,
tagValue,
} from "@welshman/util"
import {getBlob, decryptFile, makeBlossomAuthEvent, tagSpec, tagValue} from "@welshman/util"
import LinkRound from "@assets/icons/link-round.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import {user} from "@app/core"
import {getUrlTags} from "@app/content"
const {value, event, ...props} = $props()
const url = value.url.toString()
// An imeta tag packs its own tags into space-separated values, so unpack the one for this url.
const meta =
matchTags(tagSpec("imeta"), event.tags)
.map(([, ...values]: string[]) => values.map(value => value.split(" ")))
.find(meta => tagValue(tagSpec("url"), meta) === url) || event.tags
const meta = getUrlTags(url, event)
// Fallback to filename if hash was omitted from the message for interoperability
const hash = tagValue(tagSpec("x"), meta) || url.split(/[\/\.]/).slice(-2)[0]

View file

@ -1,18 +1,17 @@
<script lang="ts">
import {displayUrl} from "@welshman/lib"
import {tagSpec, tagValue} from "@welshman/util"
import {preventDefault, stopPropagation} from "@lib/html"
import LinkRound from "@assets/icons/link-round.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
import ContentLinkUrl from "@app/components/ContentLinkUrl.svelte"
import {pushModal} from "@app/modal"
import {IMAGE_CONTENT_TYPES} from "@app/content"
import {getUrlContentType, IMAGE_CONTENT_TYPES} from "@app/content"
const {value, event} = $props()
const url = value.url.toString()
const fileType = tagValue(tagSpec("file-type"), event.tags) || ""
const fileType = getUrlContentType(url, event)
const expand = () => pushModal(ContentLinkDetail, {value, event}, {fullscreen: true})
</script>

View file

@ -15,8 +15,11 @@ import {
THREAD,
ZAP_GOAL,
ZAP_RECEIPT,
matchTags,
tagSpec,
tagValue,
} from "@welshman/util"
import type {Filter} from "@welshman/util"
import type {Filter, TrustedEvent} from "@welshman/util"
import {ENABLE_ZAPS} from "@app/env"
export const IMAGE_CONTENT_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"]
@ -32,6 +35,28 @@ export const AUDIO_CONTENT_TYPES = [
"audio/flac",
]
export const getUrlTags = (url: string, event: TrustedEvent) => {
// An imeta tag packs its own tags into space-separated values, so unpack them.
const imetas = matchTags(tagSpec("imeta"), event.tags).map(([, ...values]: string[]) =>
values.map(value => value.split(" ")),
)
const imeta = imetas.find(meta => tagValue(tagSpec("url"), meta) === url)
if (imeta) {
return imeta
}
// A nip 17 file message describes its one file on the event itself, but an event carrying imeta
// has said all it has to say about each url, so any other link in it is described by nothing.
return imetas.length > 0 ? [] : event.tags
}
export const getUrlContentType = (url: string, event: TrustedEvent) => {
const tags = getUrlTags(url, event)
return tagValue(tagSpec("m"), tags) || tagValue(tagSpec("file-type"), tags) || ""
}
export const makeCommentFilter = (kinds: number[], extra: Filter = {}) => ({
kinds: [COMMENT],
"#K": kinds.map(String),