This commit is contained in:
Manav Rathi
2025-03-24 15:36:30 +05:30
parent f29ed595de
commit 2d245ea8e4
2 changed files with 64 additions and 23 deletions

View File

@@ -82,7 +82,9 @@ export const fetchFilesData = async (
*
* Unlike {@link fetchFilesData}, this uses a HTTP GET request.
*
* Returns `undefined` if no video preview has been generated for this file yet.
* Returns `undefined` if no file data of the given type has been uploaded for
* this file yet (e.g. if type was "vid_preview", this would indicate that a
* video preview has been generated for this file yet).
*/
export const fetchFileData = async (
type: FileDataType,
@@ -134,3 +136,54 @@ export const putFileData = async (
});
ensureOk(res);
};
/**
* Fetch the preview file data the given file.
*
* @param type The {@link FileDataType} which we want.
*
* @param fileIDs The id of the files for which we want the file preview data.
*
* @returns the (presigned) URL to the preview data, or undefined if there is
* not preview data of the given type for the given file yet.
*
* [Note: File data vs file preview data]
*
* In museum's ontology, there is a distinction between two concepts:
*
* S3 metadata (museum term, the APIs call it "file data") is data that museum
* uploads on behalf of the client. e.g.,
*
* - ML data.
*
* - Preview video playlist.
*
* S3 file data (museum term, the APIs call it "file preview data") is data that
* a client itself uploads. e.g.,
*
* - The preview video itself.
*
* - Additional preview images.
*
* [Note: Video playlist and preview]
*
* For a streaming video, both these concepts are needed:
*
* - The encrypted HLS playlist is stored as "file data" of type "vid_preview",
*
* - The encrypted video chunks that the playlist refers to are stored as "file
* preview data" of type "vid_preview".
*/
export const fetchFilePreviewData = async (
type: FileDataType,
fileID: number,
): Promise<string | undefined> => {
const params = new URLSearchParams({ type, fileID: fileID.toString() });
const url = await apiURL("/files/data/preview");
const res = await fetch(`${url}?${params.toString()}`, {
headers: await authenticatedRequestHeaders(),
});
if (res.status == 404) return undefined;
ensureOk(res);
return z.object({ url: z.string() }).parse(await res.json()).url;
};

View File

@@ -6,7 +6,7 @@ import { FileType } from "@/media/file-type";
import { gunzip } from "@/new/photos/utils/gzip";
import { ensurePrecondition } from "@/utils/ensure";
import { z } from "zod";
import { fetchFileData } from "./file-data";
import { fetchFileData, fetchFilePreviewData } from "./file-data";
/**
* Return a HLS playlist that can be used to stream playback of thne given video
@@ -17,26 +17,7 @@ import { fetchFileData } from "./file-data";
* @returns The HLS playlist as a string, or `undefined` if there is no video
* preview associated with the given file.
*
* [Note: Video playlist and preview]
*
* In museum's ontology, there is a distinction between two concepts:
*
* S3 metadata is the data that museum uploads (on behalf of the client):
* - ML data.
* - Preview video playlist.
*
* S3 file data is the data that client uploads:
* - Preview video itself.
* - Additional preview images.
*
* Because of this separation, there are separate code paths dealing with the
* two parts we need to play streaming video:
*
* - The encrypted HLS playlist (which is stored as file data of type
* "vid_preview"),
*
* - And the encrypted video chunks that it (the playlist) refers to (which are
* stored as file preview data of type "vid_preview").
* See: [Note: Video playlist and preview]
*/
export const hlsPlaylistForFile = async (file: EnteFile) => {
ensurePrecondition(file.metadata.fileType == FileType.video);
@@ -44,11 +25,17 @@ export const hlsPlaylistForFile = async (file: EnteFile) => {
const playlistFileData = await fetchFileData("vid_preview", file.id);
if (!playlistFileData) return undefined;
const videoURL = await fetchFilePreviewData("vid_preview", file.id);
if (!videoURL) return undefined;
// See: [Note: strict mode migration]
//
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { playlist } = await decryptPlaylistJSON(playlistFileData, file);
const { playlist: playlistTemplate } = await decryptPlaylistJSON(
playlistFileData,
file,
);
// [Note: HLS playlist format]
//
@@ -102,6 +89,7 @@ export const hlsPlaylistForFile = async (file: EnteFile) => {
// (AES-128 for us), URI and IV attributes. The URI attribute value is a
// quoted string containing a URI that specfies how to obtain the key.
const playlist = playlistTemplate.replaceAll("output.ts", videoURL);
log.debug(() => ["hlsPlaylistForFile", playlist]);
return file.id;
};