mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 13:35:42 +09:00
perf(app): load voice background tiles only near the viewport (#1971)
This commit is contained in:
1 parent
52282bfccf
commit
61bf8f6ad3
2 files changed
+348
-290
No files matched your search
@@ -8,12 +8,30 @@ export interface NativeBackgroundMediaSource {
|
||||
mediaKind: VoiceBackgroundMediaKind;
|
||||
}
|
||||
|
||||
interface BackgroundImageRead {
|
||||
cancelled: boolean;
|
||||
promise: Promise<string | null>;
|
||||
}
|
||||
|
||||
const resolvedUrls = new Map<string, string>();
|
||||
const pendingReads = new Map<string, BackgroundImageRead>();
|
||||
|
||||
async function readBackgroundImageObjectURL(id: string): Promise<string | null> {
|
||||
const readVoiceBackgroundMedia = getElectronAPI()?.readVoiceBackgroundMedia;
|
||||
if (!readVoiceBackgroundMedia) return null;
|
||||
const media = await readVoiceBackgroundMedia(id);
|
||||
if (!media?.dataUrl) return null;
|
||||
const response = await fetch(media.dataUrl);
|
||||
return URL.createObjectURL(await response.blob());
|
||||
}
|
||||
|
||||
export async function saveBackgroundImage(id: string, blob: Blob): Promise<NativeBackgroundMediaSource> {
|
||||
const cacheVoiceBackgroundMedia = getElectronAPI()?.cacheVoiceBackgroundMedia;
|
||||
if (!cacheVoiceBackgroundMedia) {
|
||||
throw new Error('Native background media cache unavailable');
|
||||
}
|
||||
const fileName = blob instanceof File ? blob.name : undefined;
|
||||
releaseBackgroundImageURL(id);
|
||||
return cacheVoiceBackgroundMedia({
|
||||
id,
|
||||
mimeType: blob.type,
|
||||
@@ -27,29 +45,48 @@ export async function deleteBackgroundImage(id: string): Promise<void> {
|
||||
if (!deleteVoiceBackgroundMedia) {
|
||||
throw new Error('Native background media cache unavailable');
|
||||
}
|
||||
releaseBackgroundImageURL(id);
|
||||
await deleteVoiceBackgroundMedia(id);
|
||||
}
|
||||
|
||||
export function dataUrlToObjectUrl(dataUrl: string): string | null {
|
||||
const match = dataUrl.match(/^data:([^;,]+)?(;base64)?,([\s\S]*)$/);
|
||||
if (!match) return null;
|
||||
const mimeType = match[1] || 'application/octet-stream';
|
||||
const isBase64 = match[2] === ';base64';
|
||||
const payload = match[3] ?? '';
|
||||
try {
|
||||
const bytes = isBase64
|
||||
? Uint8Array.from(atob(payload), (char) => char.charCodeAt(0))
|
||||
: new TextEncoder().encode(decodeURIComponent(payload));
|
||||
return URL.createObjectURL(new Blob([bytes], {type: mimeType}));
|
||||
} catch {
|
||||
return null;
|
||||
export function getCachedBackgroundImageURL(id: string): string | null {
|
||||
return resolvedUrls.get(id) ?? null;
|
||||
}
|
||||
|
||||
export function releaseBackgroundImageURL(id: string): void {
|
||||
const resolved = resolvedUrls.get(id);
|
||||
if (resolved != null) {
|
||||
URL.revokeObjectURL(resolved);
|
||||
resolvedUrls.delete(id);
|
||||
}
|
||||
const pending = pendingReads.get(id);
|
||||
if (pending != null) {
|
||||
pending.cancelled = true;
|
||||
pendingReads.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getBackgroundImageURL(id: string): Promise<string | null> {
|
||||
const readVoiceBackgroundMedia = getElectronAPI()?.readVoiceBackgroundMedia;
|
||||
if (!readVoiceBackgroundMedia) return null;
|
||||
const media = await readVoiceBackgroundMedia(id);
|
||||
if (!media?.dataUrl) return null;
|
||||
return dataUrlToObjectUrl(media.dataUrl);
|
||||
const resolved = resolvedUrls.get(id);
|
||||
if (resolved != null) return resolved;
|
||||
const inFlight = pendingReads.get(id);
|
||||
if (inFlight != null) return inFlight.promise;
|
||||
const read: BackgroundImageRead = {cancelled: false, promise: Promise.resolve(null)};
|
||||
read.promise = readBackgroundImageObjectURL(id).then(
|
||||
(url) => {
|
||||
if (read.cancelled) {
|
||||
if (url != null) URL.revokeObjectURL(url);
|
||||
return null;
|
||||
}
|
||||
pendingReads.delete(id);
|
||||
if (url != null) resolvedUrls.set(id, url);
|
||||
return url;
|
||||
},
|
||||
(error: unknown) => {
|
||||
if (!read.cancelled) pendingReads.delete(id);
|
||||
throw error;
|
||||
},
|
||||
);
|
||||
pendingReads.set(id, read);
|
||||
return read.promise;
|
||||
}
|
||||
Reference in new issue
Block a user