mirror of
https://git.v0l.io/florian/bouquet.git
synced 2025-03-17 21:13:02 +01:00
feat: Added links to posts and videos
This commit is contained in:
parent
5ef517e4ae
commit
3e6df7a246
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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} />
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user