diff --git a/web/apps/cast/src/constants/upload.ts b/web/apps/cast/src/constants/upload.ts index bc6006e46..18d9aed8b 100644 --- a/web/apps/cast/src/constants/upload.ts +++ b/web/apps/cast/src/constants/upload.ts @@ -1,11 +1,6 @@ import { ENCRYPTION_CHUNK_SIZE } from "@ente/shared/crypto/constants"; import { FILE_TYPE } from "constants/file"; -import { - FileTypeInfo, - ImportSuggestion, - Location, - ParsedExtractedMetadata, -} from "types/upload"; +import { FileTypeInfo, ImportSuggestion } from "types/upload"; // list of format that were missed by type-detection for some files. export const WHITELISTED_FILE_FORMATS: FileTypeInfo[] = [ @@ -59,8 +54,6 @@ export const FILE_CHUNKS_COMBINED_FOR_A_UPLOAD_PART = Math.floor( export const RANDOM_PERCENTAGE_PROGRESS_FOR_PUT = () => 90 + 10 * Math.random(); -export const NULL_LOCATION: Location = { latitude: null, longitude: null }; - export enum UPLOAD_STAGES { START, READING_GOOGLE_METADATA_FILES, @@ -97,13 +90,6 @@ export const MAX_FILE_SIZE_SUPPORTED = 4 * 1024 * 1024 * 1024; // 4 GB export const LIVE_PHOTO_ASSET_SIZE_LIMIT = 20 * 1024 * 1024; // 20MB -export const NULL_EXTRACTED_METADATA: ParsedExtractedMetadata = { - location: NULL_LOCATION, - creationTime: null, - width: null, - height: null, -}; - export const A_SEC_IN_MICROSECONDS = 1e6; export const DEFAULT_IMPORT_SUGGESTION: ImportSuggestion = { diff --git a/web/apps/cast/src/services/castDownloadManager.ts b/web/apps/cast/src/services/castDownloadManager.ts index b56aec928..2dea0451e 100644 --- a/web/apps/cast/src/services/castDownloadManager.ts +++ b/web/apps/cast/src/services/castDownloadManager.ts @@ -1,162 +1,14 @@ -import { EnteFile } from "types/file"; -import { - createTypedObjectURL, - generateStreamFromArrayBuffer, - getRenderableFileURL, -} from "utils/file"; - import { CustomError } from "@ente/shared/error"; import HTTPService from "@ente/shared/network/HTTPService"; -import { getCastFileURL, getCastThumbnailURL } from "@ente/shared/network/api"; -import { logError } from "@ente/shared/sentry"; -import { CACHES } from "constants/cache"; +import { getCastFileURL } from "@ente/shared/network/api"; import { FILE_TYPE } from "constants/file"; -import { LimitedCache } from "types/cache"; +import { EnteFile } from "types/file"; import ComlinkCryptoWorker from "utils/comlink/ComlinkCryptoWorker"; -import { CacheStorageService } from "./cache/cacheStorageService"; +import { generateStreamFromArrayBuffer } from "utils/file"; class CastDownloadManager { - private fileObjectURLPromise = new Map< - string, - Promise<{ original: string[]; converted: string[] }> - >(); - private thumbnailObjectURLPromise = new Map>(); - - private fileDownloadProgress = new Map(); - - private progressUpdater: (value: Map) => void; - - setProgressUpdater(progressUpdater: (value: Map) => void) { - this.progressUpdater = progressUpdater; - } - - private async getThumbnailCache() { - try { - const thumbnailCache = await CacheStorageService.open( - CACHES.THUMBS, - ); - return thumbnailCache; - } catch (e) { - return null; - // ignore - } - } - - public async getCachedThumbnail( - file: EnteFile, - thumbnailCache?: LimitedCache, - ) { - try { - if (!thumbnailCache) { - thumbnailCache = await this.getThumbnailCache(); - } - const cacheResp: Response = await thumbnailCache?.match( - file.id.toString(), - ); - - if (cacheResp) { - return URL.createObjectURL(await cacheResp.blob()); - } - return null; - } catch (e) { - logError(e, "failed to get cached thumbnail"); - throw e; - } - } - - public async getThumbnail(file: EnteFile, castToken: string) { - try { - if (!this.thumbnailObjectURLPromise.has(file.id)) { - const downloadPromise = async () => { - const thumbnailCache = await this.getThumbnailCache(); - const cachedThumb = await this.getCachedThumbnail( - file, - thumbnailCache, - ); - if (cachedThumb) { - return cachedThumb; - } - - const thumb = await this.downloadThumb(castToken, file); - const thumbBlob = new Blob([thumb]); - try { - await thumbnailCache?.put( - file.id.toString(), - new Response(thumbBlob), - ); - } catch (e) { - // TODO: handle storage full exception. - } - return URL.createObjectURL(thumbBlob); - }; - this.thumbnailObjectURLPromise.set(file.id, downloadPromise()); - } - - return await this.thumbnailObjectURLPromise.get(file.id); - } catch (e) { - this.thumbnailObjectURLPromise.delete(file.id); - logError(e, "get castDownloadManager preview Failed"); - throw e; - } - } - - private downloadThumb = async (castToken: string, file: EnteFile) => { - const resp = await HTTPService.get( - getCastThumbnailURL(file.id), - null, - { - "X-Cast-Access-Token": castToken, - }, - { responseType: "arraybuffer" }, - ); - if (typeof resp.data === "undefined") { - throw Error(CustomError.REQUEST_FAILED); - } - const cryptoWorker = await ComlinkCryptoWorker.getInstance(); - const decrypted = await cryptoWorker.decryptThumbnail( - new Uint8Array(resp.data), - await cryptoWorker.fromB64(file.thumbnail.decryptionHeader), - file.key, - ); - return decrypted; - }; - - getFile = async (file: EnteFile, castToken: string, forPreview = false) => { - const fileKey = forPreview ? `${file.id}_preview` : `${file.id}`; - try { - const getFilePromise = async () => { - const fileStream = await this.downloadFile(castToken, file); - const fileBlob = await new Response(fileStream).blob(); - if (forPreview) { - return await getRenderableFileURL(file, fileBlob); - } else { - const fileURL = await createTypedObjectURL( - fileBlob, - file.metadata.title, - ); - return { converted: [fileURL], original: [fileURL] }; - } - }; - - if (!this.fileObjectURLPromise.get(fileKey)) { - this.fileObjectURLPromise.set(fileKey, getFilePromise()); - } - const fileURLs = await this.fileObjectURLPromise.get(fileKey); - return fileURLs; - } catch (e) { - this.fileObjectURLPromise.delete(fileKey); - logError(e, "castDownloadManager failed to get file"); - throw e; - } - }; - - public async getCachedOriginalFile(file: EnteFile) { - return await this.fileObjectURLPromise.get(file.id.toString()); - } - async downloadFile(castToken: string, file: EnteFile) { const cryptoWorker = await ComlinkCryptoWorker.getInstance(); - const onDownloadProgress = this.trackDownloadProgress(file.id); if ( file.metadata.fileType === FILE_TYPE.IMAGE || @@ -187,9 +39,6 @@ class CastDownloadManager { }); const reader = resp.body.getReader(); - const contentLength = +resp.headers.get("Content-Length"); - let downloadedBytes = 0; - const stream = new ReadableStream({ async start(controller) { const decryptionHeader = await cryptoWorker.fromB64( @@ -209,10 +58,6 @@ class CastDownloadManager { // Is there more data to read? if (!done) { downloadedBytes += value.byteLength; - onDownloadProgress({ - loaded: downloadedBytes, - total: contentLength, - }); const buffer = new Uint8Array( data.byteLength + value.byteLength, ); @@ -254,20 +99,6 @@ class CastDownloadManager { }); return stream; } - - trackDownloadProgress = (fileID: number) => { - return (event: { loaded: number; total: number }) => { - if (event.loaded === event.total) { - this.fileDownloadProgress.delete(fileID); - } else { - this.fileDownloadProgress.set( - fileID, - Math.round((event.loaded * 100) / event.total), - ); - } - this.progressUpdater(new Map(this.fileDownloadProgress)); - }; - }; } export default new CastDownloadManager(); diff --git a/web/apps/cast/src/services/ffmpeg/ffmpegFactory.ts b/web/apps/cast/src/services/ffmpeg/ffmpegFactory.ts index b3c716d99..15939891a 100644 --- a/web/apps/cast/src/services/ffmpeg/ffmpegFactory.ts +++ b/web/apps/cast/src/services/ffmpeg/ffmpegFactory.ts @@ -1,5 +1,3 @@ -// import isElectron from 'is-electron'; -// import { ElectronFFmpeg } from 'services/electron/ffmpeg'; import { ElectronFile } from "types/upload"; import ComlinkFFmpegWorker from "utils/comlink/ComlinkFFmpegWorker"; @@ -16,11 +14,7 @@ class FFmpegFactory { private client: IFFmpeg; async getFFmpegClient() { if (!this.client) { - // if (isElectron()) { - // this.client = new ElectronFFmpeg(); - // } else { this.client = await ComlinkFFmpegWorker.getInstance(); - // } } return this.client; } diff --git a/web/apps/cast/src/types/upload/index.ts b/web/apps/cast/src/types/upload/index.ts index 0d38f6190..c4a05fc6d 100644 --- a/web/apps/cast/src/types/upload/index.ts +++ b/web/apps/cast/src/types/upload/index.ts @@ -3,7 +3,6 @@ import { LocalFileAttributes, } from "@ente/shared/crypto/types"; import { FILE_TYPE } from "constants/file"; -import { Collection } from "types/collection"; import { FilePublicMagicMetadata, FilePublicMagicMetadataProps, @@ -39,24 +38,6 @@ export interface Metadata { deviceFolder?: string; } -export interface Location { - latitude: number; - longitude: number; -} - -export interface ParsedMetadataJSON { - creationTime: number; - modificationTime: number; - latitude: number; - longitude: number; -} - -export interface MultipartUploadURLs { - objectKey: string; - partURLs: string[]; - completeURL: string; -} - export interface FileTypeInfo { fileType: FILE_TYPE; exactType: string; @@ -83,25 +64,11 @@ export interface ElectronFile { arrayBuffer: () => Promise; } -export interface UploadAsset { - isLivePhoto?: boolean; - file?: File | ElectronFile; - livePhotoAssets?: LivePhotoAssets; - isElectron?: boolean; -} export interface LivePhotoAssets { image: globalThis.File | ElectronFile; video: globalThis.File | ElectronFile; } -export interface FileWithCollection extends UploadAsset { - localID: number; - collection?: Collection; - collectionID?: number; -} - -export type ParsedMetadataJSONMap = Map; - export interface UploadURL { url: string; objectKey: string; diff --git a/web/apps/cast/src/utils/file/index.ts b/web/apps/cast/src/utils/file/index.ts index d3de7b76f..6dc80d898 100644 --- a/web/apps/cast/src/utils/file/index.ts +++ b/web/apps/cast/src/utils/file/index.ts @@ -1,4 +1,10 @@ +import { CustomError } from "@ente/shared/error"; +import { addLocalLog, addLogLine } from "@ente/shared/logging"; +import { isPlaybackPossible } from "@ente/shared/media/video-playback"; import { logError } from "@ente/shared/sentry"; +import { LS_KEYS, getData } from "@ente/shared/storage/localStorage"; +import { User } from "@ente/shared/user/types"; +import { convertBytesToHumanReadable } from "@ente/shared/utils/size"; import { FILE_TYPE, RAW_FORMATS, @@ -17,15 +23,6 @@ import { FileMagicMetadata, FilePublicMagicMetadata, } from "types/file"; -import { isArchivedFile } from "utils/magicMetadata"; - -import { CustomError } from "@ente/shared/error"; -import { addLocalLog, addLogLine } from "@ente/shared/logging"; -import { isPlaybackPossible } from "@ente/shared/media/video-playback"; -import { LS_KEYS, getData } from "@ente/shared/storage/localStorage"; -import { User } from "@ente/shared/user/types"; -import { convertBytesToHumanReadable } from "@ente/shared/utils/size"; -import isElectron from "is-electron"; import { FileTypeInfo } from "types/upload"; import ComlinkCryptoWorker from "utils/comlink/ComlinkCryptoWorker"; @@ -239,7 +236,7 @@ export async function getPlayableVideo( if (isPlayable && !forceConvert) { return videoBlob; } else { - if (!forceConvert && !isElectron()) { + if (!forceConvert) { return null; } addLogLine( @@ -273,19 +270,7 @@ export async function getRenderableImage(fileName: string, imageBlob: Blob) { throw Error(CustomError.UNSUPPORTED_RAW_FORMAT); } - if (!isElectron()) { - throw Error(CustomError.NOT_AVAILABLE_ON_WEB); - } - addLogLine( - `RawConverter called for ${fileName}-${convertBytesToHumanReadable( - imageBlob.size, - )}`, - ); - // convertedImageBlob = await imageProcessor.convertToJPEG( - // imageBlob, - // fileName - // ); - addLogLine(`${fileName} successfully converted`); + throw Error(CustomError.NOT_AVAILABLE_ON_WEB); } catch (e) { try { if (!isFileHEIC(exactType)) { @@ -373,10 +358,6 @@ export function getUniqueFiles(files: EnteFile[]) { export const isImageOrVideo = (fileType: FILE_TYPE) => [FILE_TYPE.IMAGE, FILE_TYPE.VIDEO].includes(fileType); -export const getArchivedFiles = (files: EnteFile[]) => { - return files.filter(isArchivedFile).map((file) => file.id); -}; - export const createTypedObjectURL = async (blob: Blob, fileName: string) => { const type = await getFileType(new File([blob], fileName)); return URL.createObjectURL(new Blob([blob], { type: type.mimeType })); @@ -495,16 +476,9 @@ export const getPreviewableImage = async ( castToken: string, ): Promise => { try { - let fileBlob: Blob; - const fileURL = - await CastDownloadManager.getCachedOriginalFile(file)[0]; - if (!fileURL) { - fileBlob = await new Response( - await CastDownloadManager.downloadFile(castToken, file), - ).blob(); - } else { - fileBlob = await (await fetch(fileURL)).blob(); - } + let fileBlob = await new Response( + await CastDownloadManager.downloadFile(castToken, file), + ).blob(); if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { const livePhoto = await decodeLivePhoto(file, fileBlob); fileBlob = new Blob([livePhoto.image]); diff --git a/web/apps/cast/src/utils/magicMetadata/index.ts b/web/apps/cast/src/utils/magicMetadata/index.ts index 7beb45772..1cbdd31d2 100644 --- a/web/apps/cast/src/utils/magicMetadata/index.ts +++ b/web/apps/cast/src/utils/magicMetadata/index.ts @@ -1,46 +1,6 @@ -import { Collection } from "types/collection"; -import { EnteFile } from "types/file"; -import { MagicMetadataCore, VISIBILITY_STATE } from "types/magicMetadata"; +import { MagicMetadataCore } from "types/magicMetadata"; import ComlinkCryptoWorker from "utils/comlink/ComlinkCryptoWorker"; -export function isArchivedFile(item: EnteFile): boolean { - if (!item || !item.magicMetadata || !item.magicMetadata.data) { - return false; - } - return item.magicMetadata.data.visibility === VISIBILITY_STATE.ARCHIVED; -} - -export function isArchivedCollection(item: Collection): boolean { - if (!item) { - return false; - } - - if (item.magicMetadata && item.magicMetadata.data) { - return item.magicMetadata.data.visibility === VISIBILITY_STATE.ARCHIVED; - } - - if (item.sharedMagicMetadata && item.sharedMagicMetadata.data) { - return ( - item.sharedMagicMetadata.data.visibility === - VISIBILITY_STATE.ARCHIVED - ); - } - return false; -} - -export function isPinnedCollection(item: Collection) { - if ( - !item || - !item.magicMetadata || - !item.magicMetadata.data || - typeof item.magicMetadata.data === "string" || - typeof item.magicMetadata.data.order === "undefined" - ) { - return false; - } - return item.magicMetadata.data.order !== 0; -} - export async function updateMagicMetadata( magicMetadataUpdates: T, originalMagicMetadata?: MagicMetadataCore,