+33
-5
src/components/PostComposer.svelte
+33
-5
src/components/PostComposer.svelte
···
43
43
client.user?.did ? generateColorForDid(client.user?.did) : 'var(--nucleus-accent2)'
44
44
);
45
45
46
+
const getVideoDimensions = (
47
+
blobUrl: string
48
+
): Promise<Result<{ width: number; height: number }, string>> =>
49
+
new Promise((resolve) => {
50
+
const video = document.createElement('video');
51
+
video.onloadedmetadata = () => {
52
+
resolve(ok({ width: video.videoWidth, height: video.videoHeight }));
53
+
};
54
+
video.onerror = (e) => resolve(err(String(e)));
55
+
video.src = blobUrl;
56
+
});
57
+
46
58
const uploadVideo = async (blobUrl: string, mimeType: string) => {
47
59
const file = await (await fetch(blobUrl)).blob();
48
60
return await client.uploadVideo(file, mimeType, (status) => {
···
56
68
}
57
69
});
58
70
};
71
+
72
+
const getImageDimensions = (
73
+
blobUrl: string
74
+
): Promise<Result<{ width: number; height: number }, string>> =>
75
+
new Promise((resolve) => {
76
+
const img = new Image();
77
+
img.onload = () => resolve(ok({ width: img.width, height: img.height }));
78
+
img.onerror = (e) => resolve(err(String(e)));
79
+
img.src = blobUrl;
80
+
});
81
+
59
82
const uploadImage = async (blobUrl: string) => {
60
83
const file = await (await fetch(blobUrl)).blob();
61
84
return await client.uploadBlob(file, (progress) => {
···
77
100
const images = _state.attachedMedia.images;
78
101
let uploadedImages: typeof images = [];
79
102
for (const image of images) {
80
-
const upload = _state.blobsState.get((image.image as AtpBlob<string>).ref.$link);
103
+
const blobUrl = (image.image as AtpBlob<string>).ref.$link;
104
+
const upload = _state.blobsState.get(blobUrl);
81
105
if (!upload || upload.state !== 'uploaded') continue;
106
+
const size = await getImageDimensions(blobUrl);
107
+
if (size.ok) image.aspectRatio = size.value;
82
108
uploadedImages.push({
83
109
...image,
84
110
image: upload.blob
···
91
117
images: uploadedImages
92
118
};
93
119
} else if (_state.attachedMedia?.$type === 'app.bsky.embed.video') {
94
-
const upload = _state.blobsState.get(
95
-
(_state.attachedMedia.video as AtpBlob<string>).ref.$link
96
-
);
97
-
if (upload && upload.state === 'uploaded')
120
+
const blobUrl = (_state.attachedMedia.video as AtpBlob<string>).ref.$link;
121
+
const upload = _state.blobsState.get(blobUrl);
122
+
if (upload && upload.state === 'uploaded') {
123
+
const size = await getVideoDimensions(blobUrl);
124
+
if (size.ok) _state.attachedMedia.aspectRatio = size.value;
98
125
media = {
99
126
..._state.attachedMedia,
100
127
$type: 'app.bsky.embed.video',
101
128
video: upload.blob
102
129
};
130
+
}
103
131
}
104
132
// console.log('media', media);
105
133
+1
-1
src/lib/at/client.svelte.ts
+1
-1
src/lib/at/client.svelte.ts
···
359
359
},
360
360
(uploaded, total) => onStatus?.({ stage: 'uploading', progress: uploaded / total })
361
361
);
362
-
if (!uploadResult.ok) return err(`failed to upload video: ${uploadResult.error.message}`);
362
+
if (!uploadResult.ok) return err(`failed to upload video: ${uploadResult.error}`);
363
363
const jobStatus = uploadResult.value;
364
364
let videoBlobRef: AtpBlob<string> = jobStatus.blob;
365
365