mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
feat(backgrounds): accept webm custom call backgrounds (#2377)
This commit is contained in:
@@ -76,7 +76,7 @@ export const ANIMATED_BANNER_FEATURE = 'ANIMATED_BANNER';
|
||||
export const STATIC_IMAGE_FORMATS = formatAssetUploadExtensions('avatar', {animatedAllowed: false});
|
||||
export const STATIC_IMAGE_WITH_AVIF_FORMATS = formatAssetUploadExtensions('splash');
|
||||
export const ANIMATED_IMAGE_FORMATS = formatAssetUploadExtensions('avatar');
|
||||
export const BACKGROUND_MEDIA_FORMATS = 'JPG, PNG, GIF, WebP, MP4';
|
||||
export const BACKGROUND_MEDIA_FORMATS = 'JPG, PNG, GIF, WebP, MP4, WebM';
|
||||
export const ANIMATED_AVATAR_FORMATS = formatKnownAnimatedAssetExtensions('avatar');
|
||||
export const AVIF_FORMAT_LABEL = 'AVIF';
|
||||
export const CUSTOM_SOUND_FORMATS = 'MP3, WAV, OGG, M4A, AAC, FLAC, Opus, WebM';
|
||||
|
||||
@@ -179,8 +179,8 @@ interface BuiltInBackground {
|
||||
type BackgroundItemType = BuiltInBackground | BackgroundImage;
|
||||
|
||||
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
||||
const ALLOWED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4'];
|
||||
const ALLOWED_FILE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'mp4'];
|
||||
const ALLOWED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4', 'video/webm'];
|
||||
const ALLOWED_FILE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'mp4', 'webm'];
|
||||
|
||||
function isAllowedBackgroundFile(file: File): boolean {
|
||||
if (ALLOWED_MIME_TYPES.includes(file.type)) {
|
||||
|
||||
@@ -8,21 +8,29 @@ export interface NativeBackgroundMediaSource {
|
||||
mediaKind: VoiceBackgroundMediaKind;
|
||||
}
|
||||
|
||||
interface BackgroundImageRead {
|
||||
cancelled: boolean;
|
||||
promise: Promise<string | null>;
|
||||
export interface BackgroundMediaObjectURL {
|
||||
url: string;
|
||||
mediaKind: VoiceBackgroundMediaKind;
|
||||
}
|
||||
|
||||
const resolvedUrls = new Map<string, string>();
|
||||
interface BackgroundImageRead {
|
||||
cancelled: boolean;
|
||||
promise: Promise<BackgroundMediaObjectURL | null>;
|
||||
}
|
||||
|
||||
const resolvedMedia = new Map<string, BackgroundMediaObjectURL>();
|
||||
const pendingReads = new Map<string, BackgroundImageRead>();
|
||||
|
||||
async function readBackgroundImageObjectURL(id: string): Promise<string | null> {
|
||||
async function readBackgroundMediaObjectURL(id: string): Promise<BackgroundMediaObjectURL | 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());
|
||||
return {
|
||||
url: URL.createObjectURL(await response.blob()),
|
||||
mediaKind: media.mediaKind,
|
||||
};
|
||||
}
|
||||
|
||||
export async function saveBackgroundImage(id: string, blob: Blob): Promise<NativeBackgroundMediaSource> {
|
||||
@@ -50,14 +58,14 @@ export async function deleteBackgroundImage(id: string): Promise<void> {
|
||||
}
|
||||
|
||||
export function getCachedBackgroundImageURL(id: string): string | null {
|
||||
return resolvedUrls.get(id) ?? null;
|
||||
return resolvedMedia.get(id)?.url ?? null;
|
||||
}
|
||||
|
||||
export function releaseBackgroundImageURL(id: string): void {
|
||||
const resolved = resolvedUrls.get(id);
|
||||
const resolved = resolvedMedia.get(id);
|
||||
if (resolved != null) {
|
||||
URL.revokeObjectURL(resolved);
|
||||
resolvedUrls.delete(id);
|
||||
URL.revokeObjectURL(resolved.url);
|
||||
resolvedMedia.delete(id);
|
||||
}
|
||||
const pending = pendingReads.get(id);
|
||||
if (pending != null) {
|
||||
@@ -66,21 +74,21 @@ export function releaseBackgroundImageURL(id: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getBackgroundImageURL(id: string): Promise<string | null> {
|
||||
const resolved = resolvedUrls.get(id);
|
||||
export async function getBackgroundMediaObjectURL(id: string): Promise<BackgroundMediaObjectURL | null> {
|
||||
const resolved = resolvedMedia.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) => {
|
||||
read.promise = readBackgroundMediaObjectURL(id).then(
|
||||
(media) => {
|
||||
if (read.cancelled) {
|
||||
if (url != null) URL.revokeObjectURL(url);
|
||||
if (media != null) URL.revokeObjectURL(media.url);
|
||||
return null;
|
||||
}
|
||||
pendingReads.delete(id);
|
||||
if (url != null) resolvedUrls.set(id, url);
|
||||
return url;
|
||||
if (media != null) resolvedMedia.set(id, media);
|
||||
return media;
|
||||
},
|
||||
(error: unknown) => {
|
||||
if (!read.cancelled) pendingReads.delete(id);
|
||||
@@ -90,3 +98,7 @@ export async function getBackgroundImageURL(id: string): Promise<string | null>
|
||||
pendingReads.set(id, read);
|
||||
return read.promise;
|
||||
}
|
||||
|
||||
export async function getBackgroundImageURL(id: string): Promise<string | null> {
|
||||
return (await getBackgroundMediaObjectURL(id))?.url ?? null;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ const MEDIA_TYPES = new Map<
|
||||
['image/gif', {mimeType: 'image/gif', extension: 'gif', mediaKind: 'animated'}],
|
||||
['image/webp', {mimeType: 'image/webp', extension: 'webp', mediaKind: 'static'}],
|
||||
['video/mp4', {mimeType: 'video/mp4', extension: 'mp4', mediaKind: 'video'}],
|
||||
['video/webm', {mimeType: 'video/webm', extension: 'webm', mediaKind: 'video'}],
|
||||
]);
|
||||
|
||||
const MEDIA_TYPES_BY_EXTENSION = new Map(Array.from(MEDIA_TYPES.values()).map((value) => [value.extension, value]));
|
||||
|
||||
Reference in New Issue
Block a user