diff --git a/src/components/AudioBlobList/AudioBlobList.tsx b/src/components/AudioBlobList/AudioBlobList.tsx
index 48e8344..0687aad 100644
--- a/src/components/AudioBlobList/AudioBlobList.tsx
+++ b/src/components/AudioBlobList/AudioBlobList.tsx
@@ -71,7 +71,7 @@ const AudioBlobList = ({ audioFiles, handleSelectBlob, selectedBlobs }: AudioBlo
{blob.data.id3 && (
- {blob.data.id3.title &&
{blob.data.id3.title}}
+ {blob.data.id3.title &&
{blob.data.id3.title}}
{blob.data.id3.artist &&
{blob.data.id3.artist}}
{blob.data.id3.album && (
diff --git a/src/components/AudioPlayer.tsx b/src/components/AudioPlayer.tsx
index 952da9d..882ba22 100644
--- a/src/components/AudioPlayer.tsx
+++ b/src/components/AudioPlayer.tsx
@@ -140,7 +140,7 @@ const AudioPlayer: React.FC = () => {
-
{currentSong.id3.title}
+
{currentSong.id3.title}
{currentSong.id3.artist}
>
diff --git a/src/components/FileEventEditor/FileEventEditor.tsx b/src/components/FileEventEditor/FileEventEditor.tsx
index 0124d83..2563b66 100644
--- a/src/components/FileEventEditor/FileEventEditor.tsx
+++ b/src/components/FileEventEditor/FileEventEditor.tsx
@@ -8,6 +8,7 @@ import { transferBlob } from '../../utils/transfer';
import { useNDK } from '../../utils/ndk';
import TagInput from '../TagInput';
import { allGenres } from '../../utils/genres';
+import { useServerInfo } from '../../utils/useServerInfo';
export type FileEventData = {
originalFile: File;
@@ -35,6 +36,7 @@ export type FileEventData = {
const FileEventEditor = ({ data }: { data: FileEventData }) => {
const { signEventTemplate } = useNDK();
+ const { serverInfo } = useServerInfo();
const [fileEventData, setFileEventData] = useState(data);
const [selectedThumbnail, setSelectedThumbnail] = useState();
@@ -78,15 +80,15 @@ const FileEventEditor = ({ data }: { data: FileEventData }) => {
}
}, [fileEventData]);
- function extractProtocolAndDomain(url: string): string | null {
- const regex = /^(https?:\/\/[^/]+)/;
+ function extractDomain(url: string): string | null {
+ const regex = /^(https?:\/\/)([^/]+)/;
const match = url.match(regex);
- return match ? match[0] : null;
+ return match ? match[2]?.toLocaleLowerCase() : null;
}
const publishSelectedThumbnailToAllOwnServers = async (): Promise => {
// TODO investigate why mimetype is not set for reuploaded thumbnail (on mediaserver)
- const servers = fileEventData.url.map(extractProtocolAndDomain);
+ const servers = fileEventData.url.map(extractDomain);
// upload selected thumbnail to the same blossom servers as the video
let uploadedThumbnails: BlobDescriptor[] = [];
@@ -94,7 +96,11 @@ const FileEventEditor = ({ data }: { data: FileEventData }) => {
uploadedThumbnails = (
await Promise.all(
servers.map(s => {
- if (s && selectedThumbnail) return transferBlob(selectedThumbnail, s, signEventTemplate);
+ if (s && selectedThumbnail) {
+ console.log(s);
+ console.log(serverInfo);
+ return transferBlob(selectedThumbnail, serverInfo[s], signEventTemplate);
+ }
})
)
).filter(t => t !== undefined) as BlobDescriptor[];
@@ -211,45 +217,47 @@ const FileEventEditor = ({ data }: { data: FileEventData }) => {
className="textarea textarea-primary"
placeholder="Caption"
>
-
- Genre
-
-
-
+
+ >
+ )}
Tags
= ({
value={imageResize}
>
{ResizeOptions.map((ro, i) => (
-
+
{ro.name}
))}
diff --git a/src/pages/Upload.tsx b/src/pages/Upload.tsx
index 63e6a41..e25752c 100644
--- a/src/pages/Upload.tsx
+++ b/src/pages/Upload.tsx
@@ -118,20 +118,22 @@ function Upload() {
try {
let newBlob: BlobDescriptor;
+ const progressHandler = (progressEvent: AxiosProgressEvent) => {
+ setTransfers(ut => ({
+ ...ut,
+ [server.name]: {
+ ...ut[server.name],
+ transferred: serverTransferred + progressEvent.loaded,
+ rate: progressEvent.rate || 0,
+ },
+ }));
+ };
if (server.type == 'blossom') {
- newBlob = await uploadBlob(serverUrl, file, uploadAuth, progressEvent => {
- setTransfers(ut => ({
- ...ut,
- [server.name]: {
- ...ut[server.name],
- transferred: serverTransferred + progressEvent.loaded,
- rate: progressEvent.rate || 0,
- },
- }));
- });
+ newBlob = await uploadBlob(serverUrl, file, uploadAuth, progressHandler);
} else {
- newBlob = await uploadNip96File(server, file, '', signEventTemplate);
+ newBlob = await uploadNip96File(server, file, '', signEventTemplate, progressHandler);
}
+ console.log('newBlob', newBlob);
serverTransferred += file.size;
setTransfers(ut => ({
...ut,
diff --git a/src/utils/blossom.ts b/src/utils/blossom.ts
index ae5b9f1..7c4194e 100644
--- a/src/utils/blossom.ts
+++ b/src/utils/blossom.ts
@@ -53,10 +53,7 @@ export const uploadBlossomBlob = async (
return res.data;
};
-export const downloadBlossomBlob = async (
- url: string,
- onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void
-) => {
+export const downloadBlossomBlob = async (url: string, onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void) => {
const response = await axios.get(url, {
responseType: 'blob',
onDownloadProgress,
@@ -92,4 +89,4 @@ export const mirrordBlossomBlob = async (
}
);
return res.data;
-};
+};
\ No newline at end of file
diff --git a/src/utils/nip96.ts b/src/utils/nip96.ts
index 9cde626..6690aa4 100644
--- a/src/utils/nip96.ts
+++ b/src/utils/nip96.ts
@@ -1,6 +1,7 @@
import { BlobDescriptor, EventTemplate, SignedEvent } from 'blossom-client-sdk';
import { Server } from './useUserServers';
import dayjs from 'dayjs';
+import axios, { AxiosProgressEvent } from 'axios';
type MediaTransformation = 'resizing' | 'format_conversion' | 'compression' | 'metadata_stripping';
@@ -74,7 +75,6 @@ async function createNip98UploadAuthToken(
],
};
const signedEvent = await signEventTemplate(authEvent);
- console.log(JSON.stringify(signedEvent));
return btoa(JSON.stringify(signedEvent));
}
@@ -82,18 +82,20 @@ const getValueByTag = (tags: string[][] | undefined, t: string) => tags && tags.
export async function fetchNip96List(
server: Server,
- signEventTemplate: (template: EventTemplate) => Promise
+ signEventTemplate: (template: EventTemplate) => Promise,
+ onProgress?: (progressEvent: AxiosProgressEvent) => void
) {
const page = 0;
const count = 100;
const baseUrl = server.nip96?.api_url || server.url;
const listUrl = `${baseUrl}?page=${page}&count=${count}`;
- const response = await fetch(listUrl, {
+ const response = await axios.get(listUrl, {
headers: { Authorization: `Nostr ${await createNip98UploadAuthToken(listUrl, 'GET', signEventTemplate)}` },
+ onDownloadProgress: onProgress,
});
- const list = (await response.json()) as Nip96ListResponse;
+ const list = response.data as Nip96ListResponse;
return list.files.map(
file =>
@@ -132,35 +134,36 @@ The server MUST link the user's pubkey string as the owner of the file so to lat
no_transform can be used to replicate a file to multiple servers for redundancy, clients can use the server list to find alternative servers which might contain the same file. When uploading a file and requesting no_transform clients should check that the hash matches in the response in order to detect if the file was modified.
*/
+
export async function uploadNip96File(
server: Server,
file: File,
caption: string,
- signEventTemplate: (template: EventTemplate) => Promise
+ signEventTemplate: (template: EventTemplate) => Promise,
+ onProgress?: (progressEvent: AxiosProgressEvent) => void
): Promise {
const formData = new FormData();
formData.append('file', file);
formData.append('caption', caption || ''); // RECOMMENDED TODO ADD
//formData.append('expiration', server.expiration || '');
formData.append('size', file.size.toString());
- //formData.append('alt', server.alt || ''); // RECOMMENDED
+ formData.append('alt', caption || ''); // RECOMMENDED
//formData.append('media_type', // avatar / banner
formData.append('content_type', file.type || '');
- formData.append('no_transform', 'true');
+ formData.append('no_transform', 'true'); // we don't use any transform for blossom compatibility
const baseUrl = server.nip96?.api_url || server.url;
- const response = await fetch(baseUrl, {
- method: 'POST',
+ const response = await axios.post(baseUrl, formData, {
headers: { Authorization: `Nostr ${await createNip98UploadAuthToken(baseUrl, 'POST', signEventTemplate)}` },
- body: formData,
+ onUploadProgress: onProgress,
});
- if (!response.ok) {
+ if (response.status >= 400) {
throw new Error(`Failed to upload file: ${response.statusText}`);
}
- const result = (await response.json()) as Nip96UploadResult;
+ const result = response.data as Nip96UploadResult;
console.log(result);
const x = getValueByTag(result.nip94_event?.tags, 'x') || getValueByTag(result.nip94_event?.tags, 'ox');
@@ -217,19 +220,18 @@ export async function deleteNip96File(
const auth = await createNip98UploadAuthToken(url, 'DELETE', signEventTemplate);
- const response = await fetch(url, {
- method: 'DELETE',
+ const response = await axios.delete(url, {
headers: {
...headers,
authorization: `Nostr ${auth}`,
},
});
- if (!response.ok) {
+ if (response.status >= 400) {
throw new Error(`Failed to delete file: ${response.statusText}`);
}
- const result = await response.json();
+ const result = response.data;
if (result.status !== 'success') {
throw new Error(`Failed to delete file: ${result.message}`);
}
diff --git a/src/utils/transfer.ts b/src/utils/transfer.ts
index 247ae7c..12fd6dd 100644
--- a/src/utils/transfer.ts
+++ b/src/utils/transfer.ts
@@ -1,6 +1,8 @@
import { AxiosProgressEvent } from 'axios';
import { BlobDescriptor, EventTemplate, SignedEvent } from 'blossom-client-sdk';
import { downloadBlossomBlob, mirrordBlossomBlob, uploadBlossomBlob } from './blossom';
+import { Server } from './useUserServers';
+import { uploadNip96File } from './nip96';
async function blobUrlToFile(blobUrl: string, fileName: string): Promise {
const response = await fetch(blobUrl);
@@ -12,26 +14,36 @@ async function blobUrlToFile(blobUrl: string, fileName: string): Promise {
// TODO support nip96
export const transferBlob = async (
sourceUrl: string,
- targetServer: string,
+ targetServer: Server,
signEventTemplate: (template: EventTemplate) => Promise,
- onUploadProgress?: (progressEvent: AxiosProgressEvent) => void
+ onProgress?: (progressEvent: AxiosProgressEvent) => void
): Promise => {
console.log({ sourceUrl, targetServer });
if (sourceUrl.startsWith('blob:')) {
const file = await blobUrlToFile(sourceUrl, 'cover.jpg');
- return await uploadBlossomBlob(targetServer, file, signEventTemplate, onUploadProgress);
+ if (targetServer.type == 'blossom') {
+ return await uploadBlossomBlob(targetServer.url, file, signEventTemplate, onProgress);
+ } else {
+ return await uploadNip96File(targetServer, file, 'cover.jpg', signEventTemplate, onProgress);
+ }
} else {
- const blob = await mirrordBlossomBlob(targetServer, sourceUrl, signEventTemplate);
- if (blob) return blob;
- console.log('Mirror failed. Using download + upload instead.');
+ if (targetServer.type == 'blossom') {
+ const blob = await mirrordBlossomBlob(targetServer.url, sourceUrl, signEventTemplate);
+ if (blob) return blob;
+ console.log('Mirror failed. Using download + upload instead.');
+ }
- const result = await downloadBlossomBlob(sourceUrl, onUploadProgress);
+ const result = await downloadBlossomBlob(sourceUrl, onProgress);
const fileName = sourceUrl.replace(/.*\//, '');
const file = new File([result.data], fileName, { type: result.type, lastModified: new Date().getTime() });
- return await uploadBlossomBlob(targetServer, file, signEventTemplate, onUploadProgress);
+ if (targetServer.type == 'blossom') {
+ return await uploadBlossomBlob(targetServer.url, file, signEventTemplate, onProgress);
+ } else {
+ return await uploadNip96File(targetServer, file, fileName, signEventTemplate, onProgress); // TODO add caption
+ }
}
};
diff --git a/tailwind.config.ts b/tailwind.config.ts
index b93af0b..8103a64 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -5,7 +5,6 @@ export default {
extend: {},
},
plugins: [require('daisyui')],
-
daisyui: {
themes: [
{
@@ -13,7 +12,7 @@ export default {
...require('daisyui/src/theming/themes')['dark'],
primary: '#be185d',
secondary: '#2563eb',
- accent: '#fb923c',
+ accent: '#ffffff',
info: '#a5b4fc',
success: '#6ee7b7',
warning: '#facc15',
@@ -25,7 +24,7 @@ export default {
...require('daisyui/src/theming/themes')['cupcake'],
primary: '#be185d',
secondary: '#2563eb',
- accent: '#fb923c',
+ accent: '#000000',
neutral: '#e0e0e0',
info: '#a5b4fc',
success: '#6ee7b7',