feat: Added links to posts and videos

This commit is contained in:
florian 2024-05-29 00:11:33 +02:00
parent 5ef517e4ae
commit 3e6df7a246
6 changed files with 104 additions and 34 deletions

View File

@ -31,13 +31,9 @@ const AudioBlobList = ({ audioFiles, onDelete }: AudioBlobListProps) => {
{audioFilesWithId3.map(
blob =>
blob.isSuccess && (
<div
key={blob.data.sha256}
className="p-4 rounded-lg bg-base-300 w-full relative flex flex-col"
>
<div key={blob.data.sha256} className="p-4 rounded-lg bg-base-300 w-full relative flex flex-col">
<div className="flex flex-row gap-4 pb-1">
<div className="cover-image" >
<div className="cover-image">
<img
width={96}
height={96}
@ -48,9 +44,10 @@ const AudioBlobList = ({ audioFiles, onDelete }: AudioBlobListProps) => {
}
/>
{state.currentSong?.url == blob.data.url ? (
<PauseIcon className="pause-icon" onClick={() =>
dispatch({ type: 'RESET_CURRENT_SONG'})
}></PauseIcon>
<PauseIcon
className="pause-icon"
onClick={() => dispatch({ type: 'RESET_CURRENT_SONG' })}
></PauseIcon>
) : (
<PlayIcon
className="play-icon"

View File

@ -1,5 +1,11 @@
import { AddressPointer } from 'nostr-tools/nip19';
import { KIND_BLOSSOM_DRIVE, KIND_FILE_META } from '../../utils/useFileMetaEvents';
import {
KIND_BLOSSOM_DRIVE,
KIND_FILE_META,
KIND_SOCIAL_POST,
KIND_VIDEO_HORIZONTAL,
KIND_VIDEO_VERTICAL,
} from '../../utils/useFileMetaEvents';
import { nip19 } from 'nostr-tools';
import { EventPointer, NDKEvent } from '@nostr-dev-kit/ndk';
@ -32,7 +38,35 @@ const Badge = ({ ev }: { ev: NDKEvent }) => {
);
}
return <></>;
if (ev.kind == KIND_VIDEO_HORIZONTAL || ev.kind == KIND_VIDEO_VERTICAL) {
const naddr = nip19.naddrEncode({
kind: ev.kind,
identifier: ev.tagValue('d'),
pubkey: ev.author.pubkey,
relays: ev.onRelays.map(r => r.url),
} as AddressPointer);
return (
<a target="_blank" className="badge badge-primary mr-2" href={`https://www.flare.pub/w/${naddr}`}>
video
</a>
);
}
if (ev.kind == KIND_SOCIAL_POST) {
const nevent = nip19.neventEncode({
kind: ev.kind,
id: ev.id,
author: ev.author.pubkey,
relays: ev.onRelays.map(r => r.url),
} as EventPointer);
return (
<a target="_blank" href={`https://njump.me/${nevent}`}>
<div className="badge badge-primary mr-2">post</div>
</a>
);
}
return <span className="badge badge-primary mr-2">{ev.kind}</span>;
};
export default Badge;

View File

@ -11,10 +11,7 @@ type DocumentBlobListProps = {
const DocumentBlobList = ({ docs, onDelete }: DocumentBlobListProps) => (
<div className="blob-list grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-2 justify-center">
{docs.map(blob => (
<div
key={blob.sha256}
className="p-4 rounded-lg bg-base-300 relative flex flex-col"
>
<div key={blob.sha256} className="p-4 rounded-lg bg-base-300 relative flex flex-col">
<a href={blob.url} target="_blank" className="block overflow-clip text-ellipsis py-2 m-auto ">
<Document file={blob.url}>
<Page pageIndex={0} width={300} renderTextLayer={false} renderAnnotationLayer={false} renderForms={false} />

View File

@ -27,6 +27,7 @@ const FileEventEditor = ({ data }: { data: FileEventData }) => {
const [fileEventData, setFileEventData] = useState(data);
const { createDvmThumbnailRequest, thumbnailRequestEventId } = useVideoThumbnailDvm(setFileEventData);
const { publishAudioEvent, publishFileEvent, publishVideoEvent } = usePublishing();
const [jsonOutput, setJsonOutput] = useState('');
useEffect(() => {
if (fileEventData.m?.startsWith('video/') && fileEventData.thumbnails == undefined) {
@ -169,16 +170,26 @@ const FileEventEditor = ({ data }: { data: FileEventData }) => {
DEVELOPMENT ZONE! These publish buttons do not work yet. Events are only shown in the browser console.
</div>
<div className="flex gap-2">
<button className="btn btn-primary" onClick={() => publishFileEvent(fileEventData)}>
<button
className="btn btn-primary"
onClick={async () => setJsonOutput(await publishFileEvent(fileEventData))}
>
Create File Event
</button>
<button className="btn btn-primary" onClick={() => publishAudioEvent(fileEventData)}>
<button
className="btn btn-primary"
onClick={async () => setJsonOutput(await publishAudioEvent(fileEventData))}
>
Create Audio Event
</button>
<button className="btn btn-primary" onClick={() => publishVideoEvent(fileEventData)}>
<button
className="btn btn-primary"
onClick={async () => setJsonOutput(await publishVideoEvent(fileEventData))}
>
Create Video Event
</button>
</div>
<div className="font-mono text-xs whitespace-pre">{jsonOutput}</div>
</div>
</>
);

View File

@ -7,7 +7,7 @@ import { useNDK } from '../../utils/ndk';
export const usePublishing = () => {
const { ndk, user } = useNDK();
const publishFileEvent = async (data: FileEventData) => {
const publishFileEvent = async (data: FileEventData): Promise<string> => {
// TODO REupload selected video thumbnail from DVM
const e: NostrEvent = {
@ -42,9 +42,10 @@ export const usePublishing = () => {
await ev.sign();
console.log(ev.rawEvent());
// await ev.publish();
return JSON.stringify(ev.rawEvent(), null, 2);
};
const publishAudioEvent = async (data: FileEventData) => {
const publishAudioEvent = async (data: FileEventData): Promise<string> => {
const e: NostrEvent = {
created_at: dayjs().unix(),
content: `${data.artist} - ${data.title}`,
@ -76,9 +77,10 @@ export const usePublishing = () => {
await ev.sign();
console.log(ev.rawEvent());
// await ev.publish();
return JSON.stringify(ev.rawEvent(), null, 2);
};
const publishVideoEvent = async (data: FileEventData) => {
const publishVideoEvent = async (data: FileEventData): Promise<string> => {
const e: NostrEvent = {
created_at: dayjs().unix(),
content: data.content,
@ -115,6 +117,7 @@ export const usePublishing = () => {
await ev.sign();
console.log(ev.rawEvent());
// await ev.publish();
return JSON.stringify(ev.rawEvent(), null, 2);
};
return {

View File

@ -1,36 +1,64 @@
import { useMemo } from 'react';
import useEvents from '../utils/useEvents';
import groupBy from 'lodash/groupBy';
import { NDKFilter } from '@nostr-dev-kit/ndk';
import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
import { useNDK } from '../utils/ndk';
import { mapValues } from 'lodash';
import { mapValues, uniq } from 'lodash';
export const KIND_FILE_META = 1063;
export const KIND_BLOSSOM_DRIVE = 30563;
export const KIND_SOCIAL_POST = 1;
export const KIND_VIDEO_HORIZONTAL = 34235;
export const KIND_VIDEO_VERTICAL = 34236;
export const KIND_AUDIO = 31337;
const blossomUrlRegex = /https?:\/\/(?:www\.)?[^\s/]+\/([a-fA-F0-9]{64})(?:\.[a-zA-Z0-9]+)?/g;
function extractHashesFromContent(text: string) {
let match;
const hashes = [];
while ((match = blossomUrlRegex.exec(text)) !== null) {
hashes.push(match[1]);
}
return hashes;
}
const extractFromEvent = (ev: NDKEvent) => {
const tags = ev.tags.filter(t => t[0] == 'x').map(t => t[1]);
const hashesFromUrls = ev.tags.filter(t => t[0] == 'url').flatMap(t => extractHashesFromContent(t[1]));
const hashesFromContent = extractHashesFromContent(ev.content);
const uniqueHashes = [...new Set([...tags, ...hashesFromUrls, ...hashesFromContent])];
return uniqueHashes.flatMap(t => ({ x: t, ev }));
};
const useFileMetaEventsByHash = () => {
const { user } = useNDK();
const fileMetaFilter = useMemo(
() => ({ kinds: [KIND_FILE_META, KIND_BLOSSOM_DRIVE], authors: [user?.pubkey] }) as NDKFilter,
() =>
({
kinds: [
KIND_FILE_META,
KIND_BLOSSOM_DRIVE,
KIND_SOCIAL_POST,
KIND_VIDEO_HORIZONTAL,
KIND_VIDEO_VERTICAL,
KIND_AUDIO,
],
authors: [user?.pubkey],
limit: 100,
}) as NDKFilter,
[user?.pubkey]
);
const fileMetaSub = useEvents(fileMetaFilter);
/*
const fileMetaEventsByHash = useMemo(() => {
const allXTags = fileMetaSub.events.flatMap(ev => ev.tags.filter(t => t[0]=='x').flatMap(t => ({x:t[1], ev})));
console.log(allXTags);
return groupBy(allXTags, item => item.x)
}, [fileMetaSub.events]);
*/
const fileMetaEventsByHash = useMemo(() => {
const allXTags = fileMetaSub.events.flatMap(ev => ev.tags.filter(t => t[0] == 'x').flatMap(t => ({ x: t[1], ev })));
const allXTags = fileMetaSub.events.flatMap(ev => extractFromEvent(ev));
const groupedByX = groupBy(allXTags, item => item.x);
return mapValues(groupedByX, v => v.map(e => e.ev));
}, [fileMetaSub]);
// console.log(fileMetaEventsByHash);
console.log(fileMetaEventsByHash);
return fileMetaEventsByHash;
};