refactor: update media processing to use width and height instead of aspect ratio

This commit is contained in:
Maze Winther
2025-07-01 01:13:14 +02:00
parent 9b37ce6610
commit 1a01871cfc
6 changed files with 335 additions and 310 deletions

View File

@ -1,81 +1,85 @@
import { toast } from "sonner";
import {
getFileType,
generateVideoThumbnail,
getMediaDuration,
getImageAspectRatio,
type MediaItem,
} from "@/stores/media-store";
// import { generateThumbnail, getVideoInfo } from "./ffmpeg-utils"; // Temporarily disabled
export interface ProcessedMediaItem extends Omit<MediaItem, "id"> {}
export async function processMediaFiles(
files: FileList | File[],
onProgress?: (progress: number) => void
): Promise<ProcessedMediaItem[]> {
const fileArray = Array.from(files);
const processedItems: ProcessedMediaItem[] = [];
const total = fileArray.length;
let completed = 0;
for (const file of fileArray) {
const fileType = getFileType(file);
if (!fileType) {
toast.error(`Unsupported file type: ${file.name}`);
continue;
}
const url = URL.createObjectURL(file);
let thumbnailUrl: string | undefined;
let duration: number | undefined;
let aspectRatio: number = 16 / 9; // Default fallback
try {
if (fileType === "image") {
// Get image aspect ratio
aspectRatio = await getImageAspectRatio(file);
} else if (fileType === "video") {
// Use basic thumbnail generation for now
const videoResult = await generateVideoThumbnail(file);
thumbnailUrl = videoResult.thumbnailUrl;
aspectRatio = videoResult.aspectRatio;
} else if (fileType === "audio") {
// For audio, use a square aspect ratio
aspectRatio = 1;
}
// Get duration for videos and audio (if not already set by FFmpeg)
if ((fileType === "video" || fileType === "audio") && !duration) {
duration = await getMediaDuration(file);
}
processedItems.push({
name: file.name,
type: fileType,
file,
url,
thumbnailUrl,
duration,
aspectRatio,
});
// Yield back to the event loop to keep the UI responsive
await new Promise((resolve) => setTimeout(resolve, 0));
completed += 1;
if (onProgress) {
const percent = Math.round((completed / total) * 100);
onProgress(percent);
}
} catch (error) {
console.error("Error processing file:", file.name, error);
toast.error(`Failed to process ${file.name}`);
URL.revokeObjectURL(url); // Clean up on error
}
}
return processedItems;
}
import { toast } from "sonner";
import {
getFileType,
generateVideoThumbnail,
getMediaDuration,
getImageDimensions,
type MediaItem,
} from "@/stores/media-store";
// import { generateThumbnail, getVideoInfo } from "./ffmpeg-utils"; // Temporarily disabled
export interface ProcessedMediaItem extends Omit<MediaItem, "id"> {}
export async function processMediaFiles(
files: FileList | File[],
onProgress?: (progress: number) => void
): Promise<ProcessedMediaItem[]> {
const fileArray = Array.from(files);
const processedItems: ProcessedMediaItem[] = [];
const total = fileArray.length;
let completed = 0;
for (const file of fileArray) {
const fileType = getFileType(file);
if (!fileType) {
toast.error(`Unsupported file type: ${file.name}`);
continue;
}
const url = URL.createObjectURL(file);
let thumbnailUrl: string | undefined;
let duration: number | undefined;
let width: number | undefined;
let height: number | undefined;
try {
if (fileType === "image") {
// Get image dimensions
const dimensions = await getImageDimensions(file);
width = dimensions.width;
height = dimensions.height;
} else if (fileType === "video") {
// Use basic thumbnail generation for now
const videoResult = await generateVideoThumbnail(file);
thumbnailUrl = videoResult.thumbnailUrl;
width = videoResult.width;
height = videoResult.height;
} else if (fileType === "audio") {
// For audio, we don't set width/height (they'll be undefined)
}
// Get duration for videos and audio (if not already set by FFmpeg)
if ((fileType === "video" || fileType === "audio") && !duration) {
duration = await getMediaDuration(file);
}
processedItems.push({
name: file.name,
type: fileType,
file,
url,
thumbnailUrl,
duration,
width,
height,
});
// Yield back to the event loop to keep the UI responsive
await new Promise((resolve) => setTimeout(resolve, 0));
completed += 1;
if (onProgress) {
const percent = Math.round((completed / total) * 100);
onProgress(percent);
}
} catch (error) {
console.error("Error processing file:", file.name, error);
toast.error(`Failed to process ${file.name}`);
URL.revokeObjectURL(url); // Clean up on error
}
}
return processedItems;
}

View File

@ -94,7 +94,8 @@ class StorageService {
type: mediaItem.type,
size: mediaItem.file.size,
lastModified: mediaItem.file.lastModified,
aspectRatio: mediaItem.aspectRatio,
width: mediaItem.width,
height: mediaItem.height,
duration: mediaItem.duration,
};
@ -118,7 +119,8 @@ class StorageService {
type: metadata.type,
file,
url,
aspectRatio: metadata.aspectRatio,
width: metadata.width,
height: metadata.height,
duration: metadata.duration,
// thumbnailUrl would need to be regenerated or cached separately
};

View File

@ -14,7 +14,8 @@ export interface MediaFileData {
type: "image" | "video" | "audio";
size: number;
lastModified: number;
aspectRatio: number;
width?: number;
height?: number;
duration?: number;
// File will be stored separately in OPFS
}
@ -38,4 +39,4 @@ declare global {
values(): AsyncIterableIterator<FileSystemHandle>;
entries(): AsyncIterableIterator<[string, FileSystemHandle]>;
}
}
}