diff --git a/web/apps/photos/src/services/ffmpeg.ts b/web/apps/photos/src/services/ffmpeg.ts index b407d9f4c..6a35f6569 100644 --- a/web/apps/photos/src/services/ffmpeg.ts +++ b/web/apps/photos/src/services/ffmpeg.ts @@ -42,8 +42,11 @@ export const generateVideoThumbnail = async ( ); try { + // Try generating thumbnail at seekTime 1 second. return await thumbnailAtTime(1); } catch (e) { + // If that fails, try again at the beginning. If even this throws, let + // it fail. return await thumbnailAtTime(0); } }; diff --git a/web/apps/photos/src/services/upload/thumbnail.ts b/web/apps/photos/src/services/upload/thumbnail.ts index 82f4486b4..68cebc708 100644 --- a/web/apps/photos/src/services/upload/thumbnail.ts +++ b/web/apps/photos/src/services/upload/thumbnail.ts @@ -1,6 +1,5 @@ -import { getFileNameSize } from "@/next/file"; import log from "@/next/log"; -import { ElectronFile } from "@/next/types/file"; +import { ElectronFile, type DesktopFilePath } from "@/next/types/file"; import { CustomErrorMessage, type Electron } from "@/next/types/ipc"; import { CustomError } from "@ente/shared/error"; import { FILE_TYPE } from "constants/file"; @@ -11,6 +10,7 @@ import { FileTypeInfo } from "types/upload"; import { isFileHEIC } from "utils/file"; import { getUint8ArrayView } from "../readerService"; import { getFileName } from "./uploadService"; +import { fopLabel } from "@/next/file"; /** Maximum width or height of the generated thumbnail */ const maxThumbnailDimension = 720; @@ -178,35 +178,23 @@ async function generateImageThumbnailUsingCanvas( return await getUint8ArrayView(thumbnailBlob); } -async function generateVideoThumbnail( - file: File | ElectronFile, - fileTypeInfo: FileTypeInfo, -) { - let thumbnail: Uint8Array; +const generateVideoThumbnail = async (fileOrPath: File | DesktopFilePath) => { try { - log.info( - `ffmpeg generateThumbnail called for ${getFileNameSize(file)}`, - ); - - const thumbnail = await FFmpegService.generateVideoThumbnail(file); - log.info( - `ffmpeg thumbnail successfully generated ${getFileNameSize(file)}`, - ); - return await getUint8ArrayView(thumbnail); + return await FFmpegService.generateVideoThumbnail(fileOrPath); } catch (e) { - log.info( - `ffmpeg thumbnail generated failed ${getFileNameSize( - file, - )} error: ${e.message}`, - ); log.error( - `failed to generate thumbnail using ffmpeg for format ${fileTypeInfo.exactType}`, + `Failed to generate thumbnail using FFmpeg for ${fopLabel(fileOrPath)}`, e, ); - thumbnail = await generateVideoThumbnailUsingCanvas(file); + // If we're on the web, try falling back to using the canvas instead. + if (fileOrPath instanceof File) { + log.info() + } + + return await generateVideoThumbnailUsingCanvas(file); } return thumbnail; -} +}; async function generateVideoThumbnailUsingCanvas(file: File | ElectronFile) { const canvas = document.createElement("canvas"); diff --git a/web/packages/next/file.ts b/web/packages/next/file.ts index 83b20f2ec..4d05225c8 100644 --- a/web/packages/next/file.ts +++ b/web/packages/next/file.ts @@ -1,4 +1,4 @@ -import type { ElectronFile } from "./types/file"; +import type { DesktopFilePath, ElectronFile } from "./types/file"; /** * The two parts of a file name - the name itself, and an (optional) extension. @@ -66,6 +66,13 @@ export const dirname = (path: string) => { return pathComponents.join("/"); }; +/** + * Return a short description of the given {@link fileOrPath} suitable for + * helping identify it in log messages. + */ +export const fopLabel = (fileOrPath: File | DesktopFilePath) => + fileOrPath instanceof File ? `File(${fileOrPath.name})` : fileOrPath.path; + export function getFileNameSize(file: File | ElectronFile) { return `${file.name}_${convertBytesToHumanReadable(file.size)}`; }