feat: supported background TTS with media session controls, closes #2099 and closes #964 (#2138)

This commit is contained in:
Huang Xin
2025-09-30 01:45:17 +08:00
committed by GitHub
parent 25b44176b9
commit 0a1e0212e2
49 changed files with 1105 additions and 57 deletions
+74
View File
@@ -0,0 +1,74 @@
export async function fetchImageAsBase64(
url: string,
options: {
targetWidth?: number;
format?: 'image/jpeg' | 'image/png' | 'image/webp';
quality?: number;
} = {},
): Promise<string> {
const { targetWidth = 256, format = 'image/jpeg', quality = 0.85 } = options;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
}
const blob = await response.blob();
const img = new Image();
img.crossOrigin = 'anonymous';
return new Promise((resolve, reject) => {
img.onload = () => {
try {
const aspectRatio = img.height / img.width;
const newWidth = targetWidth;
const newHeight = Math.round(newWidth * aspectRatio);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
reject(new Error('Failed to get canvas context'));
return;
}
canvas.width = newWidth;
canvas.height = newHeight;
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
ctx.drawImage(img, 0, 0, newWidth, newHeight);
const base64 = canvas.toDataURL(format, quality);
resolve(base64);
} catch (error) {
reject(new Error(`Failed to scale image: ${error}`));
}
};
img.onerror = () => reject(new Error('Failed to load image for scaling'));
const objectUrl = URL.createObjectURL(blob);
img.src = objectUrl;
const cleanup = () => URL.revokeObjectURL(objectUrl);
const originalOnload = img.onload;
const originalOnerror = img.onerror;
img.onload = function (ev) {
cleanup();
if (originalOnload) originalOnload.call(this, ev);
};
img.onerror = function (ev) {
cleanup();
if (originalOnerror) originalOnerror.call(this, ev);
};
});
} catch (error) {
console.error('Error fetching and encoding image:', error);
throw error;
}
}