Files
cinny/src/app/utils/saveMedia.ts
litruv 9887903f49
All checks were successful
Trigger cinny-mobile / dispatch (push) Successful in 2s
Add centralized saveMedia helpers for image, video, and file downloads.
Platforms can register a custom saver; viewers share one download/save path instead of FileSaver call sites.
2026-08-09 20:49:00 +10:00

56 lines
1.7 KiB
TypeScript

import FileSaver from 'file-saver';
import { downloadMedia } from './matrix';
import { getCurrentAccessToken } from './auth';
export type MediaSaver = (blob: Blob, filename: string) => void | Promise<void>;
let customMediaSaver: MediaSaver | null = null;
const defaultMediaSaver: MediaSaver = (blob, filename) => {
FileSaver.saveAs(blob, filename);
};
/**
* Register a platform-specific media saver (Android MediaStore, Electron dialog, etc.).
* Pass null to restore the default FileSaver path.
*
* Platforms should call this once at startup (mobile overlay / desktop shell entry).
*/
export const registerMediaSaver = (saver: MediaSaver | null): void => {
customMediaSaver = saver;
};
/**
* Persist a Blob to disk via the registered platform saver, or FileSaver by default.
*/
export const saveMediaBlob = async (blob: Blob, filename: string): Promise<void> => {
const saver = customMediaSaver ?? defaultMediaSaver;
await saver(blob, filename);
};
/**
* Fetch media (auth download or blob:/data:/http URL) and save it via [saveMediaBlob].
*/
export const downloadAndSaveMedia = async (
src: string,
filename: string,
accessToken?: string | null
): Promise<void> => {
let blob: Blob;
try {
if (src.startsWith('blob:') || src.startsWith('data:')) {
const res = await fetch(src);
if (!res.ok) throw new Error(`Failed to fetch ${src}`);
blob = await res.blob();
} else {
blob = await downloadMedia(src, accessToken ?? getCurrentAccessToken());
}
} catch (error) {
console.warn('[saveMedia] downloadMedia failed, trying fetch fallback:', error);
const res = await fetch(src);
if (!res.ok) throw error;
blob = await res.blob();
}
await saveMediaBlob(blob, filename);
};