diff --git a/packages/app/src/Element/MediaLink.tsx b/packages/app/src/Element/MediaLink.tsx
index 978f52b7..9aecad0e 100644
--- a/packages/app/src/Element/MediaLink.tsx
+++ b/packages/app/src/Element/MediaLink.tsx
@@ -1,43 +1,31 @@
-import { FileExtensionRegex } from "Const";
import { ProxyImg } from "Element/ProxyImg";
-export default function MediaLink({ link }: { link: string }) {
- const url = new URL(link);
- const extension = FileExtensionRegex.test(url.pathname.toLowerCase()) && RegExp.$1;
- switch (extension) {
- case "gif":
- case "jpg":
- case "jpeg":
- case "jfif":
- case "png":
- case "bmp":
- case "webp": {
- return ;
- }
- case "wav":
- case "mp3":
- case "ogg": {
- return ;
- }
- case "mp4":
- case "mov":
- case "mkv":
- case "avi":
- case "m4v":
- case "webm": {
- return ;
- }
- default:
- return (
- e.stopPropagation()}
- target="_blank"
- rel="noreferrer"
- className="ext">
- {url.toString()}
-
- );
+interface MediaElementProps {
+ mime: string;
+ url: string;
+ magnet?: string;
+ sha256?: string;
+ blurHash?: string;
+}
+
+export function MediaElement(props: MediaElementProps) {
+ if (props.mime.startsWith("image/")) {
+ return ;
+ } else if (props.mime.startsWith("audio/")) {
+ return ;
+ } else if (props.mime.startsWith("video/")) {
+ return ;
+ } else {
+ return (
+ e.stopPropagation()}
+ target="_blank"
+ rel="noreferrer"
+ className="ext">
+ {props.url}
+
+ );
}
}
diff --git a/packages/app/src/Element/NostrFileHeader.tsx b/packages/app/src/Element/NostrFileHeader.tsx
index ba61a5dc..c63d5604 100644
--- a/packages/app/src/Element/NostrFileHeader.tsx
+++ b/packages/app/src/Element/NostrFileHeader.tsx
@@ -1,24 +1,39 @@
-import useEventFeed from "Feed/EventFeed";
-import { NostrLink } from "Util";
-import HyperText from "Element/HyperText";
import { FormattedMessage } from "react-intl";
+import { RawEvent } from "@snort/nostr";
+
+import { findTag, NostrLink } from "Util";
+import useEventFeed from "Feed/EventFeed";
import PageSpinner from "Element/PageSpinner";
+import Reveal from "Element/Reveal";
+import { MediaElement } from "Element/MediaLink";
export default function NostrFileHeader({ link }: { link: NostrLink }) {
const ev = useEventFeed(link);
if (!ev.data) return ;
+ return ;
+}
+export function NostrFileElement({ ev }: { ev: RawEvent }) {
// assume image or embed which can be rendered by the hypertext kind
// todo: make use of hash
// todo: use magnet or other links if present
- const u = ev.data?.tags.find(a => a[0] === "u")?.[1] ?? "";
- if (u) {
- return ;
+ const u = findTag(ev, "url");
+ const x = findTag(ev, "x");
+ const m = findTag(ev, "m");
+ const blurHash = findTag(ev, "blurhash");
+ const magnet = findTag(ev, "magnet");
+
+ if (u && m) {
+ return (
+ }>
+
+
+ );
} else {
return (
-
+
);
}
diff --git a/packages/app/src/Element/Note.tsx b/packages/app/src/Element/Note.tsx
index ac6cf6a1..7fe712d1 100644
--- a/packages/app/src/Element/Note.tsx
+++ b/packages/app/src/Element/Note.tsx
@@ -29,6 +29,7 @@ import Poll from "Element/Poll";
import { EventExt } from "System/EventExt";
import useLogin from "Hooks/useLogin";
import { setBookmarked, setPinned } from "Login";
+import { NostrFileElement } from "Element/NostrFileHeader";
import messages from "./messages";
@@ -72,8 +73,13 @@ const HiddenNote = ({ children }: { children: React.ReactNode }) => {
};
export default function Note(props: NoteProps) {
- const navigate = useNavigate();
const { data: ev, related, highlight, options: opt, ignoreModeration = false } = props;
+
+ if (ev.kind === EventKind.FileHeader) {
+ return ;
+ }
+
+ const navigate = useNavigate();
const [showReactions, setShowReactions] = useState(false);
const deletions = useMemo(() => getReactions(related, ev.id, EventKind.Deletion), [related]);
const { isMuted } = useModeration();
diff --git a/packages/app/src/Element/RevealMedia.tsx b/packages/app/src/Element/RevealMedia.tsx
index 754b8b48..72ad233e 100644
--- a/packages/app/src/Element/RevealMedia.tsx
+++ b/packages/app/src/Element/RevealMedia.tsx
@@ -1,8 +1,9 @@
import { FormattedMessage } from "react-intl";
-import MediaLink from "Element/MediaLink";
+import { FileExtensionRegex } from "Const";
import Reveal from "Element/Reveal";
import useLogin from "Hooks/useLogin";
+import { MediaElement } from "Element/MediaLink";
interface RevealMediaProps {
creator: string;
@@ -18,14 +19,42 @@ export default function RevealMedia(props: RevealMediaProps) {
const hideMedia = pref.autoLoadMedia === "none" || (!isMine && hideNonFollows);
const hostname = new URL(props.link).hostname;
+ const url = new URL(props.link);
+ const extension = FileExtensionRegex.test(url.pathname.toLowerCase()) && RegExp.$1;
+ const type = (() => {
+ switch (extension) {
+ case "gif":
+ case "jpg":
+ case "jpeg":
+ case "jfif":
+ case "png":
+ case "bmp":
+ case "webp":
+ return "image";
+ case "wav":
+ case "mp3":
+ case "ogg":
+ return "audio";
+ case "mp4":
+ case "mov":
+ case "mkv":
+ case "avi":
+ case "m4v":
+ case "webm":
+ return "video";
+ default:
+ return "unknown";
+ }
+ })();
+
if (hideMedia) {
return (
}>
-
+
);
} else {
- return ;
+ return ;
}
}
diff --git a/packages/app/src/Util.ts b/packages/app/src/Util.ts
index 8b115b96..588579b1 100644
--- a/packages/app/src/Util.ts
+++ b/packages/app/src/Util.ts
@@ -5,7 +5,17 @@ import { bytesToHex } from "@noble/hashes/utils";
import { decode as invoiceDecode } from "light-bolt11-decoder";
import { bech32 } from "bech32";
import base32Decode from "base32-decode";
-import { HexKey, TaggedRawEvent, u256, EventKind, encodeTLV, NostrPrefix, decodeTLV, TLVEntryType } from "@snort/nostr";
+import {
+ HexKey,
+ TaggedRawEvent,
+ u256,
+ EventKind,
+ encodeTLV,
+ NostrPrefix,
+ decodeTLV,
+ TLVEntryType,
+ RawEvent,
+} from "@snort/nostr";
import { MetadataCache } from "Cache";
export const sha256 = (str: string | Uint8Array): u256 => {
@@ -466,7 +476,7 @@ export function chunks(arr: T[], length: number) {
return result;
}
-export function findTag(e: TaggedRawEvent, tag: string) {
+export function findTag(e: RawEvent, tag: string) {
const maybeTag = e.tags.find(evTag => {
return evTag[0] === tag;
});