2025-07-01 01:13:14 +02:00
|
|
|
import { toast } from "sonner";
|
|
|
|
|
import {
|
|
|
|
|
getFileType,
|
|
|
|
|
generateVideoThumbnail,
|
|
|
|
|
getMediaDuration,
|
|
|
|
|
getImageDimensions,
|
|
|
|
|
type MediaItem,
|
|
|
|
|
} from "@/stores/media-store";
|
2025-08-23 11:00:59 +02:00
|
|
|
import { generateThumbnail, getVideoInfo } from "./mediabunny-utils";
|
2025-07-01 01:13:14 +02:00
|
|
|
|
|
|
|
|
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;
|
2025-07-12 12:48:31 +02:00
|
|
|
let fps: number | undefined;
|
2025-07-01 01:13:14 +02:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (fileType === "image") {
|
|
|
|
|
const dimensions = await getImageDimensions(file);
|
|
|
|
|
width = dimensions.width;
|
|
|
|
|
height = dimensions.height;
|
|
|
|
|
} else if (fileType === "video") {
|
2025-07-12 12:48:31 +02:00
|
|
|
try {
|
2025-08-23 11:00:59 +02:00
|
|
|
const videoInfo = await getVideoInfo({ videoFile: file });
|
2025-07-12 12:48:31 +02:00
|
|
|
duration = videoInfo.duration;
|
|
|
|
|
width = videoInfo.width;
|
|
|
|
|
height = videoInfo.height;
|
|
|
|
|
fps = videoInfo.fps;
|
2025-07-01 01:13:14 +02:00
|
|
|
|
2025-08-23 11:00:59 +02:00
|
|
|
thumbnailUrl = await generateThumbnail({
|
|
|
|
|
videoFile: file,
|
|
|
|
|
timeInSeconds: 1,
|
|
|
|
|
});
|
2025-07-12 12:48:31 +02:00
|
|
|
} catch (error) {
|
2025-08-23 11:00:59 +02:00
|
|
|
console.warn("Video processing failed", error);
|
2025-07-12 12:48:31 +02:00
|
|
|
}
|
|
|
|
|
} else if (fileType === "audio") {
|
|
|
|
|
// For audio, we don't set width/height/fps (they'll be undefined)
|
2025-07-01 01:13:14 +02:00
|
|
|
duration = await getMediaDuration(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
processedItems.push({
|
|
|
|
|
name: file.name,
|
|
|
|
|
type: fileType,
|
|
|
|
|
file,
|
|
|
|
|
url,
|
|
|
|
|
thumbnailUrl,
|
|
|
|
|
duration,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
2025-07-12 12:48:31 +02:00
|
|
|
fps,
|
2025-07-01 01:13:14 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|