[desktop] Enable stream generation for non-internal users

This commit is contained in:
Manav Rathi
2025-05-27 17:32:07 +05:30
parent 2d8310460b
commit fac5ab5079
7 changed files with 48 additions and 31 deletions

View File

@@ -2,6 +2,12 @@
## v1.7.13 (Unreleased)
- Generate streams for videos (beta)
> Streamable videos can be enabled in Settings > Preferences. For more
> information, see the
> [video streaming FAQ](https://help.ente.io/photos/faq/video-streaming).
- Support Turkish translations.
- .

View File

@@ -8,22 +8,43 @@ description:
> [!NOTE]
>
> Video streaming is available in beta on mobile apps starting v0.9.98.
> Video streaming is available in beta on mobile apps starting v0.9.98 and on
> desktop starting v1.7.13.
### How to enable video streaming?
#### On mobile
- Open Settings -> General -> Advanced
- Switch on the toggle for `Video streaming`
#### On desktop
- Open Settings -> Preferences
- Enable the toggle for `Streamable videos`
### What happens when I enable video streaming?
#### On mobile
Enabling video streaming will start processing videos captured in the last 30
days, generating streams for each. Both local and remote videos will be
processed, so this may consume bandwidth for downloading of remote files and
uploading of the generated streams.
#### On desktop
When enabled, the desktop app will generate streams both for new uploads, and
also for all existing videos that were previously uploaded.
Stream generation is CPU intensive and can take time so the app will continue
processing them in the background. Clicking on search bar will show "Processing
videos..." when stream generation is happening.
### How can I view video streams?
### On mobile
Settings -> Backup > Backup status will show details regarding the processing
status for videos. Processed videos will have a green play button next to them.
You can open these videos by tapping on them.
@@ -34,6 +55,12 @@ play the stream.
Clicking on the `Info` icon within the original video will show details about
the generated stream.
### On desktop and web
Desktop and web app will automatically play the streaming version of a video if
it has been already generated. The quality selector will show "Auto" when
playing the stream.
### What is a stream?
Stream is an encrypted HLS file with an `.m3u8` playlist that helps play a video

View File

@@ -819,7 +819,7 @@ const Preferences: React.FC<NestedSidebarDrawerVisibilityProps> = ({
label={t("advanced")}
onClick={showAdvancedSettings}
/>
{isHLSGenerationSupported() && (
{isHLSGenerationSupported && (
<Stack>
<RowButtonGroupTitle icon={<ScienceIcon />}>
{t("labs")}

View File

@@ -22,6 +22,10 @@ import { BaseContext, deriveBaseContext } from "ente-base/context";
import log from "ente-base/log";
import { logStartupBanner } from "ente-base/log-web";
import { AppUpdate } from "ente-base/types/ipc";
import {
initVideoProcessing,
isHLSGenerationSupported,
} from "ente-gallery/services/video";
import { Notification } from "ente-new/photos/components/Notification";
import { ThemedLoadingBar } from "ente-new/photos/components/ThemedLoadingBar";
import {
@@ -46,10 +50,6 @@ import { useRouter } from "next/router";
import { useCallback, useEffect, useMemo, useState } from "react";
import { photosLogout } from "services/logout";
import {
initVideoProcessing,
isHLSGenerationSupportedTemp,
} from "ente-gallery/services/video";
import "photoswipe/dist/photoswipe.css";
import "styles/global.css";
import "styles/photoswipe.css";
@@ -112,7 +112,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
};
if (isMLSupported) initML();
if (isHLSGenerationSupportedTemp()) void initVideoProcessing();
if (isHLSGenerationSupported) void initVideoProcessing();
electron.onOpenEnteURL(handleOpenEnteURL);
electron.onAppUpdateAvailable(showUpdateDialog);

View File

@@ -45,7 +45,6 @@ import {
import { FileType, type FileTypeInfo } from "ente-media/file-type";
import { encodeLivePhoto } from "ente-media/live-photo";
import { addToCollection } from "ente-new/photos/services/collection";
import { settingsSnapshot } from "ente-new/photos/services/settings";
import {
CustomError,
CustomErrorMessage,
@@ -1105,11 +1104,7 @@ const extractImageOrVideoMetadata = async (
// Video duration
let duration: number | undefined;
if (
fileType == FileType.video &&
// TODO(HLS):
settingsSnapshot().isInternalUser
) {
if (fileType == FileType.video) {
duration = await tryDetermineVideoDuration(uploadItem);
}

View File

@@ -23,7 +23,6 @@ import {
getLocalTrashFileIDs,
uniqueFilesByID,
} from "ente-new/photos/services/files";
import { settingsSnapshot } from "ente-new/photos/services/settings";
import { gunzip, gzip } from "ente-new/photos/utils/gzip";
import { randomSample } from "ente-utils/array";
import { ensurePrecondition } from "ente-utils/ensure";
@@ -208,18 +207,8 @@ const updateSnapshotIfNeeded = (
/**
* Return `true` if this client is capable of generating HLS streams for
* uploaded videos.
*
* This function implementation is fast and can be called many times (e.g.
* during UI rendering).
*/
export const isHLSGenerationSupported = () =>
// Keep this check fast, we get called many times.
isDesktop &&
// TODO(HLS):
settingsSnapshot().isInternalUser;
// TODO(HLS): Only the isDesktop flag is needed eventually.
export const isHLSGenerationSupportedTemp = () => isDesktop;
export const isHLSGenerationSupported = isDesktop;
/**
* Initialize the video processing subsystem if the user has enabled HLS
@@ -257,7 +246,7 @@ const saveGenerateHLS = (enabled: boolean) => setKV("generateHLS", enabled);
* Precondition: {@link isHLSGenerationSupported} must be `true`.
*/
export const toggleHLSGeneration = async () => {
if (!isHLSGenerationSupported()) {
if (!isHLSGenerationSupported) {
assertionFailed();
return;
}
@@ -673,7 +662,7 @@ const syncProcessedFileIDs = async () =>
export const videoPrunePermanentlyDeletedFileIDsIfNeeded = async (
deletedFileIDs: Set<number>,
) => {
if (!isHLSGenerationSupported()) return;
if (!isHLSGenerationSupported) return;
const existing = await savedProcessedVideoFileIDs();
if (existing.size > 0) {
@@ -702,7 +691,7 @@ export const videoPrunePermanentlyDeletedFileIDsIfNeeded = async (
* that have already been processed elsewhere.
*/
export const videoProcessingSyncIfNeeded = async () => {
if (!isHLSGenerationSupported()) return;
if (!isHLSGenerationSupported) return;
// The `haveSyncedOnce` flag tracks whether or not a sync has happened for
// the app, and is not specific to video processing. We always set it even
@@ -745,7 +734,7 @@ export const processVideoNewUpload = (
file: EnteFile,
processableUploadItem: ProcessableUploadItem,
) => {
if (!isHLSGenerationSupported()) return;
if (!isHLSGenerationSupported) return;
if (!isHLSGenerationEnabled()) return;
if (file.metadata.fileType !== FileType.video) return;
if (processableUploadItem instanceof File) {
@@ -830,7 +819,7 @@ export const isHLSGenerationEnabled = () => _state.isHLSGenerationEnabled;
* batches, and the externally triggered processing of live uploads.
*/
const processQueue = async () => {
if (!isHLSGenerationSupported() || !isHLSGenerationEnabled()) {
if (!isHLSGenerationSupported || !isHLSGenerationEnabled()) {
assertionFailed(); /* we shouldn't have come here */
return;
}

View File

@@ -389,7 +389,7 @@ const shouldShowEmptyState = (inputValue: string) => {
// Don't show empty state if there is no ML related information AND we're
// not processing videos.
if (!isMLSupported && !isHLSGenerationSupported()) {
if (!isMLSupported && !isHLSGenerationSupported) {
// Neither of ML or HLS generation is supported on current client. This
// is the code path for web.
return false;