Fix file download
This commit is contained in:
parent
68bfe9118a
commit
7cd7676cb0
5 changed files with 83 additions and 100 deletions
|
@ -4,8 +4,11 @@ import Theatre from 'components/Theatre';
|
|||
import { FILE_TYPE } from 'constants/file';
|
||||
import { useRouter } from 'next/router';
|
||||
import { createContext, useEffect, useState } from 'react';
|
||||
import { getCollectionWithKey } from 'services/collectionService';
|
||||
import { syncFiles } from 'services/fileService';
|
||||
import {
|
||||
getCastCollection,
|
||||
getLocalFiles,
|
||||
syncPublicFiles,
|
||||
} from 'services/cast/castService';
|
||||
import { EnteFile } from 'types/file';
|
||||
import { downloadFileAsBlob, isRawFileFromFileName } from 'utils/file';
|
||||
|
||||
|
@ -22,6 +25,7 @@ export default function Slideshow() {
|
|||
const [nextFile, setNextFile] = useState<EnteFile | undefined>(undefined);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [castToken, setCastToken] = useState<string>('');
|
||||
|
||||
const [renderableFileURLCache, setRenderableFileURLCache] = useState<
|
||||
Record<string, string>
|
||||
|
@ -29,28 +33,21 @@ export default function Slideshow() {
|
|||
|
||||
const init = async () => {
|
||||
try {
|
||||
// get requested collection id from localStorage
|
||||
const requestedCollectionID =
|
||||
window.localStorage.getItem('collectionID');
|
||||
|
||||
const requestedCollectionKey =
|
||||
window.localStorage.getItem('collectionKey');
|
||||
const castToken = window.localStorage.getItem('castToken');
|
||||
setCastToken(castToken);
|
||||
|
||||
const collection = await getCollectionWithKey(
|
||||
Number(requestedCollectionID),
|
||||
requestedCollectionKey,
|
||||
'cast',
|
||||
castToken
|
||||
const collection = await getCastCollection(
|
||||
castToken,
|
||||
requestedCollectionKey
|
||||
);
|
||||
|
||||
const files = await syncFiles('normal', [collection], () => {});
|
||||
|
||||
if (requestedCollectionID) {
|
||||
setCollectionFiles(
|
||||
files.filter((file) => isFileEligibleForCast(file))
|
||||
);
|
||||
}
|
||||
await syncPublicFiles(castToken, collection, () => {});
|
||||
const files = await getLocalFiles(String(collection.id));
|
||||
setCollectionFiles(
|
||||
files.filter((file) => isFileEligibleForCast(file))
|
||||
);
|
||||
} catch (e) {
|
||||
logError(e, 'error during sync');
|
||||
alert('error, redirect to home' + e);
|
||||
|
@ -122,7 +119,10 @@ export default function Slideshow() {
|
|||
}
|
||||
|
||||
try {
|
||||
const blob = await downloadFileAsBlob(currentFile as EnteFile);
|
||||
const blob = await downloadFileAsBlob(
|
||||
currentFile as EnteFile,
|
||||
castToken
|
||||
);
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
import { getEndpoint } from '@ente/shared/network/api';
|
||||
import localForage from '@ente/shared/storage/localForage';
|
||||
import { Collection, CollectionPublicMagicMetadata } from 'types/collection';
|
||||
import HTTPService from '@ente/shared/network/HTTPService';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
import { decryptFile, mergeMetadata, sortFiles } from 'utils/file';
|
||||
import { EncryptedEnteFile, EnteFile } from 'types/file';
|
||||
|
||||
import { CustomError, parseSharingErrorCodes } from '@ente/shared/error';
|
||||
import ComlinkCryptoWorker from '@ente/shared/crypto';
|
||||
|
||||
import { Collection, CollectionPublicMagicMetadata } from 'types/collection';
|
||||
import { EncryptedEnteFile, EnteFile } from 'types/file';
|
||||
import { decryptFile, mergeMetadata, sortFiles } from 'utils/file';
|
||||
|
||||
export interface SavedCollectionFiles {
|
||||
collectionUID: string;
|
||||
collectionLocalID: string;
|
||||
files: EnteFile[];
|
||||
}
|
||||
const ENDPOINT = getEndpoint();
|
||||
const COLLECTION_FILES_TABLE = 'collection-files';
|
||||
const COLLECTIONS_TABLE = 'collections';
|
||||
|
||||
export const getPublicCollectionUID = (token: string) => `${token}`;
|
||||
|
||||
const getLastSyncKey = (collectionUID: string) => `${collectionUID}-time`;
|
||||
|
||||
export const getLocalFiles = async (
|
||||
|
@ -29,11 +27,12 @@ export const getLocalFiles = async (
|
|||
COLLECTION_FILES_TABLE
|
||||
)) || [];
|
||||
const matchedCollection = localSavedcollectionFiles.find(
|
||||
(item) => item.collectionUID === collectionUID
|
||||
(item) => item.collectionLocalID === collectionUID
|
||||
);
|
||||
return matchedCollection?.files || [];
|
||||
};
|
||||
export const savecollectionFiles = async (
|
||||
|
||||
const savecollectionFiles = async (
|
||||
collectionUID: string,
|
||||
files: EnteFile[]
|
||||
) => {
|
||||
|
@ -43,7 +42,10 @@ export const savecollectionFiles = async (
|
|||
)) || [];
|
||||
await localForage.setItem(
|
||||
COLLECTION_FILES_TABLE,
|
||||
dedupeCollectionFiles([{ collectionUID, files }, ...collectionFiles])
|
||||
dedupeCollectionFiles([
|
||||
{ collectionLocalID: collectionUID, files },
|
||||
...collectionFiles,
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -58,7 +60,7 @@ export const getLocalCollections = async (collectionKey: string) => {
|
|||
return collection;
|
||||
};
|
||||
|
||||
export const saveCollection = async (collection: Collection) => {
|
||||
const saveCollection = async (collection: Collection) => {
|
||||
const collections =
|
||||
(await localForage.getItem<Collection[]>(COLLECTIONS_TABLE)) ?? [];
|
||||
await localForage.setItem(
|
||||
|
@ -81,7 +83,7 @@ const dedupeCollections = (collections: Collection[]) => {
|
|||
|
||||
const dedupeCollectionFiles = (collectionFiles: SavedCollectionFiles[]) => {
|
||||
const keySet = new Set([]);
|
||||
return collectionFiles.filter(({ collectionUID }) => {
|
||||
return collectionFiles.filter(({ collectionLocalID: collectionUID }) => {
|
||||
if (!keySet.has(collectionUID)) {
|
||||
keySet.add(collectionUID);
|
||||
return true;
|
||||
|
@ -108,14 +110,11 @@ export const syncPublicFiles = async (
|
|||
try {
|
||||
let files: EnteFile[] = [];
|
||||
const sortAsc = collection?.pubMagicMetadata?.data.asc ?? false;
|
||||
const collectionUID = getPublicCollectionUID(token);
|
||||
const collectionUID = String(collection.id);
|
||||
const localFiles = await getLocalFiles(collectionUID);
|
||||
|
||||
files = [...files, ...localFiles];
|
||||
console.log('found local files', files);
|
||||
try {
|
||||
if (!token) {
|
||||
return sortFiles(files, sortAsc);
|
||||
}
|
||||
const lastSyncTime = await getSyncTime(collectionUID);
|
||||
if (collection.updationTime === lastSyncTime) {
|
||||
return sortFiles(files, sortAsc);
|
||||
|
@ -165,7 +164,7 @@ export const syncPublicFiles = async (
|
|||
};
|
||||
|
||||
const fetchFiles = async (
|
||||
token: string,
|
||||
castToken: string,
|
||||
collection: Collection,
|
||||
sinceTime: number,
|
||||
files: EnteFile[],
|
||||
|
@ -177,17 +176,17 @@ const fetchFiles = async (
|
|||
let resp;
|
||||
const sortAsc = collection?.pubMagicMetadata?.data.asc ?? false;
|
||||
do {
|
||||
if (!token) {
|
||||
if (!castToken) {
|
||||
break;
|
||||
}
|
||||
resp = await HTTPService.get(
|
||||
`${ENDPOINT}/public-collection/diff`,
|
||||
`${ENDPOINT}/cast/diff`,
|
||||
{
|
||||
sinceTime: time,
|
||||
},
|
||||
{
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Auth-Access-Token': token,
|
||||
'X-Cast-Access-Token': castToken,
|
||||
}
|
||||
);
|
||||
decryptedFiles = [
|
||||
|
@ -225,18 +224,14 @@ const fetchFiles = async (
|
|||
};
|
||||
|
||||
export const getCastCollection = async (
|
||||
token: string,
|
||||
castToken: string,
|
||||
collectionKey: string
|
||||
): Promise<[Collection]> => {
|
||||
): Promise<Collection> => {
|
||||
try {
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
const resp = await HTTPService.get(
|
||||
`${ENDPOINT}/public-collection/info`,
|
||||
null,
|
||||
{ 'Cache-Control': 'no-cache', 'X-Auth-Access-Token': token }
|
||||
);
|
||||
const resp = await HTTPService.get(`${ENDPOINT}/cast/info`, null, {
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Cast-Access-Token': castToken,
|
||||
});
|
||||
const fetchedCollection = resp.data.collection;
|
||||
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
|
@ -268,9 +263,9 @@ export const getCastCollection = async (
|
|||
pubMagicMetadata: collectionPublicMagicMetadata,
|
||||
};
|
||||
await saveCollection(collection);
|
||||
return [collection];
|
||||
return collection;
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get public collection');
|
||||
logError(e, 'failed to get cast collection');
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
@ -297,7 +292,8 @@ export const removeCollectionFiles = async (collectionUID: string) => {
|
|||
await localForage.setItem(
|
||||
COLLECTION_FILES_TABLE,
|
||||
collectionFiles.filter(
|
||||
(collectionFiles) => collectionFiles.collectionUID !== collectionUID
|
||||
(collectionFiles) =>
|
||||
collectionFiles.collectionLocalID !== collectionUID
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import { CACHES } from 'constants/cache';
|
|||
import { CacheStorageService } from './cache/cacheStorageService';
|
||||
import { LimitedCache } from 'types/cache';
|
||||
import {
|
||||
getPublicCollectionFileURL,
|
||||
getCastFileURL,
|
||||
getPublicCollectionThumbnailURL,
|
||||
} from '@ente/shared/network/api';
|
||||
import HTTPService from '@ente/shared/network/HTTPService';
|
||||
|
@ -185,11 +185,8 @@ class CastDownloadManager {
|
|||
return await this.fileObjectURLPromise.get(file.id.toString());
|
||||
}
|
||||
|
||||
async downloadFile(token: string, passwordToken: string, file: EnteFile) {
|
||||
async downloadFile(castToken: string, file: EnteFile) {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
const onDownloadProgress = this.trackDownloadProgress(file.id);
|
||||
|
||||
if (
|
||||
|
@ -197,14 +194,10 @@ class CastDownloadManager {
|
|||
file.metadata.fileType === FILE_TYPE.LIVE_PHOTO
|
||||
) {
|
||||
const resp = await HTTPService.get(
|
||||
getPublicCollectionFileURL(file.id),
|
||||
getCastFileURL(file.id),
|
||||
null,
|
||||
{
|
||||
'X-Auth-Access-Token': token,
|
||||
...(passwordToken && {
|
||||
'X-Auth-Access-Token-JWT': passwordToken,
|
||||
onDownloadProgress,
|
||||
}),
|
||||
'X-Cast-Access-Token': castToken,
|
||||
},
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
|
@ -218,12 +211,9 @@ class CastDownloadManager {
|
|||
);
|
||||
return generateStreamFromArrayBuffer(decrypted);
|
||||
}
|
||||
const resp = await fetch(getPublicCollectionFileURL(file.id), {
|
||||
const resp = await fetch(getCastFileURL(file.id), {
|
||||
headers: {
|
||||
'X-Auth-Access-Token': token,
|
||||
...(passwordToken && {
|
||||
'X-Auth-Access-Token-JWT': passwordToken,
|
||||
}),
|
||||
'X-Cast-Access-Token': castToken,
|
||||
},
|
||||
});
|
||||
const reader = resp.body.getReader();
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from 'types/file';
|
||||
import { decodeLivePhoto } from 'services/livePhotoService';
|
||||
import { getFileType } from 'services/typeDetectionService';
|
||||
import DownloadManager from 'services/downloadManager';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
import { updateFileCreationDateInEXIF } from 'services/upload/exifService';
|
||||
import {
|
||||
|
@ -88,39 +87,25 @@ export async function getUpdatedEXIFFileForDownload(
|
|||
|
||||
export async function downloadFile(
|
||||
file: EnteFile,
|
||||
accessedThroughSharedURL: boolean,
|
||||
token?: string,
|
||||
passwordToken?: string
|
||||
) {
|
||||
try {
|
||||
let fileBlob: Blob;
|
||||
const fileReader = new FileReader();
|
||||
if (accessedThroughSharedURL) {
|
||||
const fileURL = await CastDownloadManager.getCachedOriginalFile(
|
||||
file
|
||||
)[0];
|
||||
if (!fileURL) {
|
||||
fileBlob = await new Response(
|
||||
await CastDownloadManager.downloadFile(
|
||||
token,
|
||||
passwordToken,
|
||||
file
|
||||
)
|
||||
).blob();
|
||||
} else {
|
||||
fileBlob = await (await fetch(fileURL)).blob();
|
||||
}
|
||||
const fileURL = await CastDownloadManager.getCachedOriginalFile(
|
||||
file
|
||||
)[0];
|
||||
if (!fileURL) {
|
||||
fileBlob = await new Response(
|
||||
await CastDownloadManager.downloadFile(
|
||||
token,
|
||||
passwordToken,
|
||||
file
|
||||
)
|
||||
).blob();
|
||||
} else {
|
||||
const fileURL = await DownloadManager.getCachedOriginalFile(
|
||||
file
|
||||
)[0];
|
||||
if (!fileURL) {
|
||||
fileBlob = await new Response(
|
||||
await DownloadManager.downloadFile(file)
|
||||
).blob();
|
||||
} else {
|
||||
fileBlob = await (await fetch(fileURL)).blob();
|
||||
}
|
||||
fileBlob = await (await fetch(fileURL)).blob();
|
||||
}
|
||||
|
||||
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
||||
|
@ -844,14 +829,18 @@ const deleteFileHelper = async (
|
|||
}
|
||||
};
|
||||
|
||||
export const downloadFileAsBlob = async (file: EnteFile): Promise<Blob> => {
|
||||
export const downloadFileAsBlob = async (
|
||||
file: EnteFile,
|
||||
castToken: string
|
||||
): Promise<Blob> => {
|
||||
try {
|
||||
let fileBlob: Blob;
|
||||
// const fileReader = new FileReader();
|
||||
const fileURL = await DownloadManager.getCachedOriginalFile(file)[0];
|
||||
const fileURL = await CastDownloadManager.getCachedOriginalFile(
|
||||
file
|
||||
)[0];
|
||||
if (!fileURL) {
|
||||
fileBlob = await new Response(
|
||||
await DownloadManager.downloadFile(file)
|
||||
await CastDownloadManager.downloadFile(castToken, file)
|
||||
).blob();
|
||||
} else {
|
||||
fileBlob = await (await fetch(fileURL)).blob();
|
||||
|
|
|
@ -28,6 +28,14 @@ export const getPublicCollectionFileURL = (id: number) => {
|
|||
return `https://public-albums.ente.io/download/?fileID=${id}`;
|
||||
};
|
||||
|
||||
export const getCastFileURL = (id: number) => {
|
||||
const endpoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT;
|
||||
if (isDevDeployment() && endpoint) {
|
||||
return `${endpoint}/cast/files/download/${id}`;
|
||||
}
|
||||
return `https://cast-albums.ente.io/download/?fileID=${id}`;
|
||||
};
|
||||
|
||||
export const getThumbnailURL = (id: number) => {
|
||||
const endpoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT;
|
||||
if (isDevDeployment() && endpoint) {
|
||||
|
|
Loading…
Add table
Reference in a new issue