This commit is contained in:
Manav Rathi 2024-04-24 21:12:56 +05:30
parent 852fc7830f
commit 34d44f599d
No known key found for this signature in database
7 changed files with 35 additions and 54 deletions

View file

@ -43,7 +43,7 @@ import mime from "mime-types";
import { AppContext } from "pages/_app";
import { getLocalCollections } from "services/collectionService";
import downloadManager from "services/download";
import { deduceFileTypeInfo } from "services/typeDetectionService";
import { detectFileTypeInfo } from "services/typeDetectionService";
import uploadManager from "services/upload/uploadManager";
import { EnteFile } from "types/file";
import { FileWithCollection } from "types/upload";
@ -486,7 +486,7 @@ const ImageEditorOverlay = (props: IProps) => {
if (!canvasRef.current) return;
const editedFile = await getEditedFile();
const fileType = await deduceFileTypeInfo(editedFile);
const fileType = await detectFileTypeInfo(editedFile);
const tempImgURL = URL.createObjectURL(
new Blob([editedFile], { type: fileType.mimeType }),
);

View file

@ -46,7 +46,7 @@ import { GalleryContext } from "pages/gallery";
import downloadManager, { LoadedLivePhotoSourceURL } from "services/download";
import { getParsedExifData } from "services/exif";
import { trashFiles } from "services/fileService";
import { deduceFileTypeInfo } from "services/typeDetectionService";
import { detectFileTypeInfo } from "services/typeDetectionService";
import { SetFilesDownloadProgressAttributesCreator } from "types/gallery";
import { isClipboardItemPresent } from "utils/common";
import { pauseVideo, playVideo } from "utils/photoFrame";
@ -594,7 +594,7 @@ function PhotoViewer(props: Iprops) {
.image;
fileObject = await getFileFromURL(url, file.metadata.title);
}
const fileTypeInfo = await deduceFileTypeInfo(fileObject);
const fileTypeInfo = await detectFileTypeInfo(fileObject);
const exifData = await getParsedExifData(
fileObject,
fileTypeInfo,

View file

@ -2,7 +2,7 @@ import { FILE_TYPE } from "@/media/file-type";
import log from "@/next/log";
import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time";
import type { FixOption } from "components/FixCreationTime";
import { deduceFileTypeInfo } from "services/typeDetectionService";
import { detectFileTypeInfo } from "services/typeDetectionService";
import { EnteFile } from "types/file";
import {
changeFileCreationTime,
@ -53,7 +53,7 @@ export async function updateCreationTimeWithExif(
[fileBlob],
file.metadata.title,
);
const fileTypeInfo = await deduceFileTypeInfo(fileObject);
const fileTypeInfo = await detectFileTypeInfo(fileObject);
const exifData = await getParsedExifData(
fileObject,
fileTypeInfo,

View file

@ -4,23 +4,18 @@ import {
KnownNonMediaFileExtensions,
type FileTypeInfo,
} from "@/media/file-type";
import log from "@/next/log";
import { nameAndExtension } from "@/next/file";
import { ElectronFile } from "@/next/types/file";
import { CustomError } from "@ente/shared/error";
import FileType, { type FileTypeResult } from "file-type";
import { getFileExtension } from "utils/file";
import { getUint8ArrayView } from "./readerService";
const TYPE_VIDEO = "video";
const TYPE_IMAGE = "image";
const CHUNK_SIZE_FOR_TYPE_DETECTION = 4100;
/**
* Read the file's initial contents or use the file's name to deduce its type.
* Read the file's initial contents or use the file's name to detect its type.
*
* This function first reads an initial chunk of the file and tries to deduce
* This function first reads an initial chunk of the file and tries to detect
* the file's {@link FileTypeInfo} from it. If that doesn't work, it then falls
* back to using the file's name to deduce it.
* back to using the file's name to detect it.
*
* If neither of these two approaches work, it throws an exception.
*
@ -32,9 +27,9 @@ const CHUNK_SIZE_FOR_TYPE_DETECTION = 4100;
* user's local filesystem. It is only valid to provide a path if we're running
* in the context of our desktop app.
*
* @returns The deduced {@link FileTypeInfo}.
* @returns The detected {@link FileTypeInfo}.
*/
export const deduceFileTypeInfo = async (
export const detectFileTypeInfo = async (
fileOrPath: File | ElectronFile,
): Promise<FileTypeInfo> => {
try {
@ -53,14 +48,14 @@ export const deduceFileTypeInfo = async (
throw Error(CustomError.INVALID_MIME_TYPE(typeResult.mime));
}
switch (mimTypeParts[0]) {
case TYPE_IMAGE:
case "image":
fileType = FILE_TYPE.IMAGE;
break;
case TYPE_VIDEO:
case "video":
fileType = FILE_TYPE.VIDEO;
break;
default:
throw Error(CustomError.NON_MEDIA_FILE);
throw new Error(CustomError.UNSUPPORTED_FILE_FORMAT);
}
return {
fileType,
@ -68,27 +63,20 @@ export const deduceFileTypeInfo = async (
mimeType: typeResult.mime,
};
} catch (e) {
const fileFormat = getFileExtension(fileOrPath.name);
const whiteListedFormat = KnownFileTypeInfos.find(
(a) => a.exactType === fileFormat,
);
if (whiteListedFormat) {
return whiteListedFormat;
}
if (KnownNonMediaFileExtensions.includes(fileFormat)) {
const [, extension] = nameAndExtension(fileOrPath.name);
const known = KnownFileTypeInfos.find((f) => f.exactType == extension);
if (known) return known;
if (KnownNonMediaFileExtensions.includes(extension))
throw Error(CustomError.UNSUPPORTED_FILE_FORMAT);
}
if (e.message === CustomError.NON_MEDIA_FILE) {
log.error(`unsupported file format ${fileFormat}`, e);
throw Error(CustomError.UNSUPPORTED_FILE_FORMAT);
}
log.error(`type detection failed for format ${fileFormat}`, e);
throw new Error(`type detection failed ${fileFormat}`);
throw e;
}
};
async function extractFileType(file: File) {
const fileBlobChunk = file.slice(0, CHUNK_SIZE_FOR_TYPE_DETECTION);
const chunkSizeForTypeDetection = 4100;
const fileBlobChunk = file.slice(0, chunkSizeForTypeDetection);
const fileDataChunk = await getUint8ArrayView(fileBlobChunk);
return getFileTypeFromBuffer(fileDataChunk);
}
@ -104,13 +92,7 @@ async function extractElectronFileType(file: ElectronFile) {
async function getFileTypeFromBuffer(buffer: Uint8Array) {
const result = await FileType.fromBuffer(buffer);
if (!result?.mime) {
let logableInfo = "";
try {
logableInfo = `result: ${JSON.stringify(result)}`;
} catch (e) {
logableInfo = "failed to stringify result";
}
throw Error(`mimetype missing from file type result - ${logableInfo}`);
throw Error(`Could not deduce MIME type from buffer`);
}
return result;
}

View file

@ -48,7 +48,7 @@ import { readStream } from "utils/native-stream";
import { hasFileHash } from "utils/upload";
import * as convert from "xml-js";
import { getFileStream } from "../readerService";
import { deduceFileTypeInfo } from "../typeDetectionService";
import { detectFileTypeInfo } from "../typeDetectionService";
import { extractAssetMetadata } from "./metadata";
import publicUploadHttpClient from "./publicUploadHttpClient";
import type { ParsedMetadataJSON } from "./takeout";
@ -331,14 +331,14 @@ const getAssetFileType = ({
}: UploadAsset) => {
return isLivePhoto
? getLivePhotoFileType(livePhotoAssets)
: deduceFileTypeInfo(file);
: detectFileTypeInfo(file);
};
const getLivePhotoFileType = async (
livePhotoAssets: LivePhotoAssets,
): Promise<FileTypeInfo> => {
const imageFileTypeInfo = await deduceFileTypeInfo(livePhotoAssets.image);
const videoFileTypeInfo = await deduceFileTypeInfo(livePhotoAssets.video);
const imageFileTypeInfo = await detectFileTypeInfo(livePhotoAssets.image);
const videoFileTypeInfo = await detectFileTypeInfo(livePhotoAssets.video);
return {
fileType: FILE_TYPE.LIVE_PHOTO,
exactType: `${imageFileTypeInfo.exactType}+${videoFileTypeInfo.exactType}`,

View file

@ -19,7 +19,7 @@ import {
updateFilePublicMagicMetadata,
} from "services/fileService";
import { heicToJPEG } from "services/heic-convert";
import { deduceFileTypeInfo } from "services/typeDetectionService";
import { detectFileTypeInfo } from "services/typeDetectionService";
import {
EncryptedEnteFile,
EnteFile,
@ -130,19 +130,19 @@ export async function downloadFile(file: EnteFile) {
const { imageFileName, imageData, videoFileName, videoData } =
await decodeLivePhoto(file.metadata.title, fileBlob);
const image = new File([imageData], imageFileName);
const imageType = await deduceFileTypeInfo(image);
const imageType = await detectFileTypeInfo(image);
const tempImageURL = URL.createObjectURL(
new Blob([imageData], { type: imageType.mimeType }),
);
const video = new File([videoData], videoFileName);
const videoType = await deduceFileTypeInfo(video);
const videoType = await detectFileTypeInfo(video);
const tempVideoURL = URL.createObjectURL(
new Blob([videoData], { type: videoType.mimeType }),
);
downloadUsingAnchor(tempImageURL, imageFileName);
downloadUsingAnchor(tempVideoURL, videoFileName);
} else {
const fileType = await deduceFileTypeInfo(
const fileType = await detectFileTypeInfo(
new File([fileBlob], file.metadata.title),
);
fileBlob = await new Response(
@ -305,7 +305,7 @@ export const getRenderableImage = async (fileName: string, imageBlob: Blob) => {
let fileTypeInfo: FileTypeInfo;
try {
const tempFile = new File([imageBlob], fileName);
fileTypeInfo = await deduceFileTypeInfo(tempFile);
fileTypeInfo = await detectFileTypeInfo(tempFile);
log.debug(
() =>
`Obtaining renderable image for ${JSON.stringify(fileTypeInfo)}`,
@ -724,7 +724,7 @@ export const getArchivedFiles = (files: EnteFile[]) => {
};
export const createTypedObjectURL = async (blob: Blob, fileName: string) => {
const type = await deduceFileTypeInfo(new File([blob], fileName));
const type = await detectFileTypeInfo(new File([blob], fileName));
return URL.createObjectURL(new Blob([blob], { type: type.mimeType }));
};

View file

@ -67,7 +67,6 @@ export const CustomError = {
AUTH_KEY_NOT_FOUND: "auth key not found",
EXIF_DATA_NOT_FOUND: "exif data not found",
SELECT_FOLDER_ABORTED: "select folder aborted",
NON_MEDIA_FILE: "non media file",
PROCESSING_FAILED: "processing failed",
EXPORT_RECORD_JSON_PARSING_FAILED: "export record json parsing failed",
TWO_FACTOR_ENABLED: "two factor enabled",