62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import { accounts } from "$lib/stores/accounts.svelte";
|
|
import { auth } from "$lib/stores/auth.svelte";
|
|
|
|
const BASE = import.meta.env.VITE_API_BASE ?? "/api";
|
|
const FILENAME_STAR = /filename\*=UTF-8''([^;]+)/i;
|
|
const FILENAME_PLAIN = /filename="?([^";]+)"?/i;
|
|
|
|
function nameFromHeader(header: string | null, fallback: string): string {
|
|
if (!header) {
|
|
return fallback;
|
|
}
|
|
const encoded = FILENAME_STAR.exec(header);
|
|
if (encoded) {
|
|
return decodeURIComponent(encoded[1]);
|
|
}
|
|
const plain = FILENAME_PLAIN.exec(header);
|
|
return plain ? plain[1] : fallback;
|
|
}
|
|
|
|
function saveBlob(blob: Blob, fileName: string) {
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = fileName;
|
|
document.body.append(link);
|
|
link.click();
|
|
link.remove();
|
|
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
}
|
|
|
|
async function save(path: string, fallback: string): Promise<void> {
|
|
const response = await fetch(`${BASE}${path}`, {
|
|
headers: auth.token ? { Authorization: `Bearer ${auth.token}` } : {},
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`download failed: ${response.status}`);
|
|
}
|
|
const fileName = nameFromHeader(
|
|
response.headers.get("content-disposition"),
|
|
fallback
|
|
);
|
|
saveBlob(await response.blob(), fileName);
|
|
}
|
|
|
|
export function downloadMedia(mediaId: number): Promise<void> {
|
|
return save(`/media/${mediaId}?download=true`, `media_${mediaId}`);
|
|
}
|
|
|
|
export function downloadMediaVersion(versionId: number): Promise<void> {
|
|
return save(
|
|
`/media/version/${versionId}?download=true`,
|
|
`media_${versionId}`
|
|
);
|
|
}
|
|
|
|
export function downloadStory(peerId: number, storyId: number): Promise<void> {
|
|
return save(
|
|
`/stories/${peerId}/${storyId}/media?download=true&account_id=${accounts.selectedId}`,
|
|
`story_${peerId}_${storyId}`
|
|
);
|
|
}
|