import { CLASSIFIED, COMMENT, DELETE, DIRECT_MESSAGE, DIRECT_MESSAGE_FILE, EVENT_TIME, GENERIC_REPOST, PINBOARD, LONG_FORM, POLL, REACTION, REPORT, REPOST, THREAD, ZAP_GOAL, ZAP_RECEIPT, matchTags, tagSpec, tagValue, } 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"] export const VIDEO_CONTENT_TYPES = ["video/quicktime", "video/webm", "video/mp4"] export const AUDIO_CONTENT_TYPES = [ "audio/mpeg", "audio/mp4", "audio/wav", "audio/x-wav", "audio/ogg", "audio/webm", "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), ...extra, }) export const makeDeleteFilter = (kinds: number[], extra: Filter = {}) => ({ kinds: [DELETE], "#k": kinds.map(String), ...extra, }) export const REPOST_KINDS = [REPOST, GENERIC_REPOST] export const EVENT_CONTEXT_KINDS = [REPORT, REACTION, ZAP_RECEIPT, COMMENT] export const REACTION_KINDS = [REPORT, DELETE, REACTION] if (ENABLE_ZAPS) { REACTION_KINDS.push(ZAP_RECEIPT) } export const CONTENT_KINDS = [ZAP_GOAL, EVENT_TIME, THREAD, CLASSIFIED, POLL, PINBOARD, LONG_FORM] const CONTENT_NOUNS = new Map([ [ZAP_GOAL, ["goal", "goals"]], [EVENT_TIME, ["event", "events"]], [THREAD, ["thread", "threads"]], [CLASSIFIED, ["classified", "classifieds"]], [POLL, ["poll", "polls"]], [PINBOARD, ["pinboard", "pinboards"]], [LONG_FORM, ["article", "articles"]], ]) export const displayContentCount = (kind: number, count: number) => { const [singular, plural] = CONTENT_NOUNS.get(kind) ?? ["item", "items"] return `${count} ${count === 1 ? singular : plural}` } export const DM_KINDS = [DIRECT_MESSAGE, DIRECT_MESSAGE_FILE] export const displayReaction = (content: string) => { if (!content || content === "+") { return "❤️" } if (content === "-") { return "👎" } return content }