mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-18 11:13:30 +00:00
replace void.cat with nostr.build
This commit is contained in:
parent
4019623d99
commit
2389ad5fdc
20
src-tauri/Cargo.lock
generated
20
src-tauri/Cargo.lock
generated
@ -2777,6 +2777,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
@ -3828,6 +3838,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
@ -5543,6 +5554,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
|
@ -35,6 +35,7 @@ tauri = { version = "1.4.0", features = [
|
||||
"window-center",
|
||||
"dialog-all",
|
||||
"macos-private-api",
|
||||
"http-multipart",
|
||||
] }
|
||||
tauri-plugin-sql = { git = "hhttps://github.com/tauri-apps/plugins-workspace", branch = "v1", features = [
|
||||
"sqlite",
|
||||
|
@ -7,8 +7,8 @@ import { convert } from 'html-to-text';
|
||||
import { useState } from 'react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
import { MentionPopup } from '@shared/composer';
|
||||
import { CancelIcon, LoaderIcon, MediaIcon } from '@shared/icons';
|
||||
import { MediaUploader, MentionPopup } from '@shared/composer';
|
||||
import { CancelIcon, LoaderIcon } from '@shared/icons';
|
||||
import { MentionNote } from '@shared/notes';
|
||||
|
||||
import { useComposer } from '@stores/composer';
|
||||
@ -20,7 +20,7 @@ export function Composer() {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [reply, clearReply] = useComposer((state) => [state.reply, state.clearReply]);
|
||||
|
||||
const { publish, upload } = useNostr();
|
||||
const { publish } = useNostr();
|
||||
|
||||
const expand = useComposer((state) => state.expand);
|
||||
const editor = useEditor({
|
||||
@ -46,14 +46,6 @@ export function Composer() {
|
||||
},
|
||||
});
|
||||
|
||||
const uploadImage = async (file?: string) => {
|
||||
const image = await upload(file, true);
|
||||
if (image.url) {
|
||||
editor.commands.setImage({ src: image.url });
|
||||
editor.commands.createParagraphNear();
|
||||
}
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@ -148,14 +140,7 @@ export function Composer() {
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded-b-xl border-t border-white/10 bg-white/5 p-2">
|
||||
<div className="inline-flex items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => uploadImage()}
|
||||
className="ml-2 inline-flex h-10 w-max items-center justify-center gap-1.5 rounded-lg px-2 text-sm font-medium text-white/80 hover:bg-white/10 hover:backdrop-blur-xl"
|
||||
>
|
||||
<MediaIcon className="h-5 w-5 text-white/80" />
|
||||
Add media
|
||||
</button>
|
||||
<MediaUploader editor={editor} />
|
||||
<MentionPopup editor={editor} />
|
||||
</div>
|
||||
<button
|
||||
|
@ -3,3 +3,4 @@ export * from './modal';
|
||||
export * from './composer';
|
||||
export * from './mention/item';
|
||||
export * from './mention/popup';
|
||||
export * from './mediaUploader';
|
||||
|
43
src/shared/composer/mediaUploader.tsx
Normal file
43
src/shared/composer/mediaUploader.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { message } from '@tauri-apps/api/dialog';
|
||||
import { Editor } from '@tiptap/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { MediaIcon } from '@shared/icons';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function MediaUploader({ editor }: { editor: Editor }) {
|
||||
const { upload } = useNostr();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const uploadImage = async (file?: string) => {
|
||||
try {
|
||||
// start loading
|
||||
setLoading(true);
|
||||
|
||||
const image = await upload(file, true);
|
||||
if (image.url) {
|
||||
editor.commands.setImage({ src: image.url });
|
||||
editor.commands.createParagraphNear();
|
||||
|
||||
// stop loading
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
// stop loading
|
||||
setLoading(false);
|
||||
await message('Upload failed', { title: 'Lume', type: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => uploadImage()}
|
||||
className="ml-2 inline-flex h-10 w-max items-center justify-center gap-1.5 rounded-lg px-2 text-sm font-medium text-white/80 hover:bg-white/10 hover:backdrop-blur-xl"
|
||||
>
|
||||
<MediaIcon className="h-5 w-5 text-white/80" />
|
||||
{loading ? 'Uploading...' : 'Add media'}
|
||||
</button>
|
||||
);
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import { readBinaryFile } from '@tauri-apps/api/fs';
|
||||
|
||||
export async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
export async function createBlobFromFile(path: string): Promise<Uint8Array> {
|
||||
const file = await readBinaryFile(path);
|
||||
return new Blob([file]);
|
||||
const blob = new Blob([file]);
|
||||
const arr = new Uint8Array(await blob.arrayBuffer());
|
||||
return arr;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { magnetDecode } from '@ctrl/magnet-link';
|
||||
import {
|
||||
NDKEvent,
|
||||
NDKFilter,
|
||||
@ -9,7 +8,7 @@ import {
|
||||
} from '@nostr-dev-kit/ndk';
|
||||
import { ndkAdapter } from '@nostr-fetch/adapter-ndk';
|
||||
import { message, open } from '@tauri-apps/api/dialog';
|
||||
import { VoidApi } from '@void-cat/api';
|
||||
import { Body, fetch } from '@tauri-apps/api/http';
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import { NostrFetcher } from 'nostr-fetch';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
@ -22,7 +21,7 @@ import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
import { createBlobFromFile } from '@utils/createBlobFromFile';
|
||||
import { nHoursAgo } from '@utils/date';
|
||||
import { NDKEventWithReplies } from '@utils/types';
|
||||
import { NDKEventWithReplies, NostrBuildResponse } from '@utils/types';
|
||||
|
||||
export function useNostr() {
|
||||
const { ndk, relayUrls } = useNDK();
|
||||
@ -330,9 +329,8 @@ export function useNostr() {
|
||||
|
||||
const upload = async (file: null | string, nip94?: boolean) => {
|
||||
try {
|
||||
const voidcat = new VoidApi('https://void.cat');
|
||||
|
||||
let filepath = file;
|
||||
|
||||
if (!file) {
|
||||
const selected = await open({
|
||||
multiple: false,
|
||||
@ -369,32 +367,37 @@ export function useNostr() {
|
||||
const filename = filepath.split('/').pop();
|
||||
const filetype = filename.split('.').pop();
|
||||
|
||||
const blob = await createBlobFromFile(filepath);
|
||||
const uploader = voidcat.getUploader(blob);
|
||||
|
||||
// upload file
|
||||
const res = await uploader.upload();
|
||||
const fileData = await createBlobFromFile(filepath);
|
||||
const res: NostrBuildResponse = await fetch(
|
||||
'https://nostr.build/api/v2/upload/files',
|
||||
{
|
||||
method: 'POST',
|
||||
timeout: 30,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
body: Body.form({
|
||||
fileData: {
|
||||
file: fileData,
|
||||
mime: `image/${filetype}`,
|
||||
fileName: filename,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (res.ok) {
|
||||
const url =
|
||||
res.file?.metadata?.url ?? `https://void.cat/d/${res.file?.id}.${filetype}`;
|
||||
const data = res.data.data[0];
|
||||
const url = data.url;
|
||||
|
||||
if (nip94) {
|
||||
const tags = [
|
||||
['url', url],
|
||||
['x', res.file?.metadata?.digest ?? ''],
|
||||
['m', res.file?.metadata?.mimeType ?? 'application/octet-stream'],
|
||||
['size', res.file?.metadata?.size.toString() ?? '0'],
|
||||
['x', data.sha256 ?? ''],
|
||||
['m', data.mime ?? 'application/octet-stream'],
|
||||
['size', data.size.toString() ?? '0'],
|
||||
['dim', `${data.dimensions.width}x${data.dimensions.height}` ?? '0'],
|
||||
['blurhash', data.blurhash ?? ''],
|
||||
];
|
||||
|
||||
if (res.file?.metadata?.magnetLink) {
|
||||
tags.push(['magnet', res.file.metadata.magnetLink]);
|
||||
const parsedMagnet = magnetDecode(res.file.metadata.magnetLink);
|
||||
if (parsedMagnet?.infoHash) {
|
||||
tags.push(['i', parsedMagnet?.infoHash]);
|
||||
}
|
||||
}
|
||||
|
||||
await publish({ content: '', kind: 1063, tags: tags });
|
||||
}
|
||||
|
||||
|
21
src/utils/types.d.ts
vendored
21
src/utils/types.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import { NDKEvent, NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { Response } from '@tauri-apps/api/http';
|
||||
|
||||
export interface RichContent {
|
||||
parsed: string;
|
||||
@ -88,3 +89,23 @@ export interface Opengraph {
|
||||
export interface NDKEventWithReplies extends NDKEvent {
|
||||
replies: Array<NDKEvent>;
|
||||
}
|
||||
|
||||
export interface NostrBuildResponse extends Response {
|
||||
ok: boolean;
|
||||
data: {
|
||||
message: string;
|
||||
status: string;
|
||||
data: Array<{
|
||||
blurhash: string;
|
||||
dimensions: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
mime: string;
|
||||
name: string;
|
||||
sha256: string;
|
||||
size: number;
|
||||
url: string;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user