This commit is contained in:
Manav Rathi 2024-05-04 12:19:18 +05:30
parent 882af50507
commit b520996af5
No known key found for this signature in database
2 changed files with 99 additions and 28 deletions

View file

@ -3,31 +3,53 @@ import { PairedSuccessfullyOverlay } from "components/PairedSuccessfullyOverlay"
import { SlideView } from "components/Slide";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import {
createRenderableURL,
getCastCollection,
getLocalFiles,
isFileEligibleForCast,
readCastData,
syncPublicFiles,
} from "services/cast";
import { Collection } from "types/collection";
import { EnteFile } from "types/file";
import { readCastData, renderableURLs } from "services/cast";
export default function Slideshow() {
const [loading, setLoading] = useState(true);
const [castToken, setCastToken] = useState<string>("");
const [castCollection, setCastCollection] = useState<
Collection | undefined
>();
const [collectionFiles, setCollectionFiles] = useState<EnteFile[]>([]);
const [currentFileId, setCurrentFileId] = useState<number | undefined>();
// const [castCollection, setCastCollection] = useState<
// Collection | undefined
// >();
// const [collectionFiles, setCollectionFiles] = useState<EnteFile[]>([]);
// const [currentFileId, setCurrentFileId] = useState<number | undefined>();
const [currentFileURL, setCurrentFileURL] = useState<string | undefined>();
const [nextFileURL, setNextFileURL] = useState<string | undefined>();
const [urlGenerator, setURLGenerator] = useState<
AsyncGenerator | undefined
>();
// const [canCast, setCanCast] = useState(false);
const router = useRouter();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const syncCastFiles = async (token: string) => {
try {
setURLGenerator(renderableURLs(readCastData()));
// setCanCast(true);
setLoading(false);
} catch (e) {
log.error("Failed to prepare URL generator", e);
// Go back to pairing page
router.push("/");
}
};
const advance = async () => {
if (!urlGenerator) throw new Error("Unexpected state");
const urls = await urlGenerator.next();
if (!urls) {
log.warn("Empty collection");
// Go back to pairing page
router.push("/");
return;
}
setCurrentFileURL(urls[0]);
setNextFileURL(urls[1]);
};
/*
const syncCastFiles0 = async (token: string) => {
try {
const { castToken, collectionKey } = readCastData();
const collection = await getCastCollection(
@ -51,6 +73,7 @@ export default function Slideshow() {
router.push("/");
}
};
*/
useEffect(() => {
if (castToken) {
@ -80,6 +103,7 @@ export default function Slideshow() {
}
}, []);
/*
useEffect(() => {
if (collectionFiles.length < 1) return;
showNextSlide();
@ -141,6 +165,7 @@ export default function Slideshow() {
console.log("error in showNextSlide", e);
}
};
*/
useEffect(() => {
if (loading) return;
@ -148,7 +173,8 @@ export default function Slideshow() {
console.log("showing slide");
const timeoutId = window.setTimeout(() => {
console.log("showing next slide timer");
showNextSlide();
// showNextSlide();
advance();
}, 10000);
return () => {

View file

@ -3,7 +3,7 @@ import { isNonWebImageFileExtension } from "@/media/formats";
import { decodeLivePhoto } from "@/media/live-photo";
import { nameAndExtension } from "@/next/file";
import log from "@/next/log";
import { ensure } from "@/utils/ensure";
import { ensureString } from "@/utils/ensure";
import ComlinkCryptoWorker from "@ente/shared/crypto";
import { CustomError, parseSharingErrorCodes } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
@ -54,14 +54,59 @@ interface CastData {
/**
* Read back the cast data we got after pairing.
*
* Sibling of {@link storeCastData}
* Sibling of {@link storeCastData}. It throws an error if the expected data is
* not present in localStorage.
*/
export const readCastData = (): CastData => {
const collectionKey = ensure(window.localStorage.getItem("collectionKey"));
const castToken = ensure(window.localStorage.getItem("castToken"));
const collectionKey = ensureString(localStorage.getItem("collectionKey"));
const castToken = ensureString(localStorage.getItem("castToken"));
return { collectionKey, castToken };
};
/**
* An async generator function that loops through all the files in the
* collection, returning renderable URLs to each that can be displayed in a
* slideshow.
*
* Each time it resolves with a pair of URLs, one for the current slideshow
* image, and one for the image to be displayed next.
*
* Once it reaches the end of the collection, it starts from the beginning
* again.
*
* It ignores errors in the fetching and decoding of individual images in the
* collection, and just moves onward to the next one. It will however throw if
* there are errors in getting the collection itself.
*
* If there are no renderable image in the collection, it resolves with
* `undefined`.
*
* @param castData The collection to show and credentials to fetch the files
* within it.
*/
export const renderableURLs = async function* (castData: CastData) {
const { collectionKey, castToken } = castData;
let previousURL: string | undefined
while (true) {
const collection = await getCollection(castToken, collectionKey);
await syncPublicFiles(castToken, collection, () => {});
const allFiles = await getLocalFiles(String(collection.id));
const files = allFiles.filter((file) => isFileEligibleForCast(file));
for (const file of files) {
if (!previousURL) {
previousURL = await createRenderableURL(castToken, file);
continue;
}
const url = await createRenderableURL(castToken, file);
const urls = [previousURL, url];
previousURL = url;
yield urls;
}
}
};
const getLastSyncKey = (collectionUID: string) => `${collectionUID}-time`;
export const getLocalFiles = async (
@ -147,8 +192,8 @@ async function getSyncTime(collectionUID: string): Promise<number> {
const updateSyncTime = async (collectionUID: string, time: number) =>
await localForage.setItem(getLastSyncKey(collectionUID), time);
export const syncPublicFiles = async (
token: string,
const syncPublicFiles = async (
castToken: string,
collection: Collection,
setPublicFiles: (files: EnteFile[]) => void,
) => {
@ -164,7 +209,7 @@ export const syncPublicFiles = async (
return sortFiles(files, sortAsc);
}
const fetchedFiles = await fetchFiles(
token,
castToken,
collection,
lastSyncTime,
files,
@ -267,9 +312,9 @@ const fetchFiles = async (
}
};
export const getCastCollection = async (
collectionKey: string,
const getCollection = async (
castToken: string,
collectionKey: string,
): Promise<Collection> => {
try {
const resp = await HTTPService.get(`${ENDPOINT}/cast/info`, null, {
@ -408,12 +453,12 @@ export function mergeMetadata(files: EnteFile[]): EnteFile[] {
* Once we're done showing the file, the URL should be revoked using
* {@link URL.revokeObjectURL} to free up browser resources.
*/
export const createRenderableURL = async (file: EnteFile, castToken: string) =>
URL.createObjectURL(await getPreviewableImage(file, castToken));
export const createRenderableURL = async (castToken: string, file: EnteFile) =>
URL.createObjectURL(await getPreviewableImage(castToken, file));
export const getPreviewableImage = async (
file: EnteFile,
castToken: string,
file: EnteFile,
): Promise<Blob> => {
try {
let fileBlob = await downloadFile(castToken, file);