This commit is contained in:
Manav Rathi
2025-04-07 17:29:17 +05:30
parent 901b3df9f5
commit 8ee3fb84b1
2 changed files with 65 additions and 15 deletions

View File

@@ -253,6 +253,13 @@ export const fileViewerDidClose = () => {
}
};
/**
* Options to modify the default behaviour of {@link itemDataForFile}.
*/
export interface ItemDataOpts {
videoQuality?: "auto" | "original";
}
/**
* Return the best available {@link ItemData} for rendering the given
* {@link file}.
@@ -264,6 +271,8 @@ export const fileViewerDidClose = () => {
* At each step, we call the provided callback so that file viewer can call us
* again to get the updated data.
*
* @param opts Options to modify the default behaviours.
*
* ---
*
* Detailed flow:
@@ -304,15 +313,18 @@ export const fileViewerDidClose = () => {
* next time the data is requested we repeat the process instead of continuing
* to serve the incomplete result.
*/
export const itemDataForFile = (file: EnteFile, needsRefresh: () => void) => {
export const itemDataForFile = (
file: EnteFile,
opts: ItemDataOpts | undefined,
needsRefresh: () => void,
) => {
const fileID = file.id;
const fileType = file.metadata.fileType;
const validTill = _state.itemDataValidTillByFileID.get(fileID);
if (validTill && validTill < new Date()) {
// Don't use the cached entry if it has become stale.
_state.itemDataByFileID.delete(fileID);
_state.itemDataValidTillByFileID.delete(fileID);
forgetItemDataForFileID(fileID);
}
let itemData = _state.itemDataByFileID.get(fileID);
@@ -325,12 +337,23 @@ export const itemDataForFile = (file: EnteFile, needsRefresh: () => void) => {
itemData = { fileID, fileType, isContentLoading: true };
_state.itemDataByFileID.set(file.id, itemData);
_state.itemDataValidTillByFileID.delete(fileID);
void enqueueUpdates(file);
void enqueueUpdates(file, opts);
}
return itemData;
};
/**
* Forget item data for the given {@link file}.
*
* This is called when we change the options passed to {@link itemDataForFile},
* and so would like to clear any previously cached data.
*/
export const forgetItemDataForFileID = (fileID: number) => {
_state.itemDataByFileID.delete(fileID);
_state.itemDataValidTillByFileID.delete(fileID);
};
/**
* Forget item data for the given {@link file} if its fetch had failed.
*
@@ -338,10 +361,8 @@ export const itemDataForFile = (file: EnteFile, needsRefresh: () => void) => {
* full retry when they come back the next time.
*/
export const forgetFailedItemDataForFileID = (fileID: number) => {
if (_state.itemDataByFileID.get(fileID)?.fetchFailed) {
_state.itemDataByFileID.delete(fileID);
_state.itemDataValidTillByFileID.delete(fileID);
}
if (_state.itemDataByFileID.get(fileID)?.fetchFailed)
forgetItemDataForFileID(fileID);
};
/**
@@ -366,7 +387,10 @@ export const updateItemDataAlt = (updatedFile: EnteFile) => {
const forgetFailedItems = () =>
[..._state.itemDataByFileID.keys()].forEach(forgetFailedItemDataForFileID);
const enqueueUpdates = async (file: EnteFile) => {
const enqueueUpdates = async (
file: EnteFile,
opts: ItemDataOpts | undefined,
) => {
const fileID = file.id;
const fileType = file.metadata.fileType;
@@ -427,7 +451,10 @@ const enqueueUpdates = async (file: EnteFile) => {
try {
if (isDevBuild && process.env.NEXT_PUBLIC_ENTE_WIP_VIDEO_STREAMING) {
if (file.metadata.fileType == FileType.video) {
if (
file.metadata.fileType == FileType.video &&
opts?.videoQuality != "original"
) {
const playlistData = await hlsPlaylistDataForFile(file);
if (playlistData) {
const {

View File

@@ -12,9 +12,11 @@ import {
fileViewerWillOpen,
forgetExifForItemData,
forgetFailedItemDataForFileID,
forgetItemDataForFileID,
itemDataForFile,
updateFileInfoExifIfNeeded,
type ItemData,
type ItemDataOpts,
} from "./data-source";
import {
type FileViewerAnnotatedFile,
@@ -297,6 +299,12 @@ export class FileViewerPhotoSwipe {
const currentFileAnnotation = () => currentAnnotatedFile().annotation;
/**
* File (ID)s for which we should render the original, non-streamable,
* video even if a HLS playlist is available.
*/
const originalVideoFileIDs = new Set<number>();
// Provide data about slides to PhotoSwipe via callbacks
// https://photoswipe.com/data-sources/#dynamically-generated-data
@@ -306,7 +314,13 @@ export class FileViewerPhotoSwipe {
const files = delegate.getFiles();
const file = files[index]!;
const itemData = itemDataForFile(file, () =>
const opts: ItemDataOpts = {
videoQuality: originalVideoFileIDs.has(file.id)
? "original"
: "auto",
};
const itemData = itemDataForFile(file, opts, () =>
pswp.refreshSlideContent(index),
);
@@ -785,11 +799,20 @@ export class FileViewerPhotoSwipe {
if (currentFileAnnotation().showDownload) handleDownload();
};
const videoQuality = "auto";
const onVideoQualityChange = () => {
// Currently there are only two entries in the video quality menu,
// and the callback only gets invoked if the value gets changed from
// the current value. So we can assume toggle semantics when
// implementing the logic below.
const onVideoQualityChange = (qualityMenu: MediaChromeMenu) => {
const newQuality = qualityMenu.value;
console.log(videoQuality, newQuality);
const fileID = currentAnnotatedFile().file.id;
forgetItemDataForFileID(fileID);
if (originalVideoFileIDs.has(fileID)) {
originalVideoFileIDs.delete(fileID);
} else {
originalVideoFileIDs.add(fileID);
}
this.refreshCurrentSlideContent();
};
const showIf = (element: HTMLElement, condition: boolean) =>