[desktop] Enable stream generation for non-internal users
This commit is contained in:
@@ -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.
|
||||
- .
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -819,7 +819,7 @@ const Preferences: React.FC<NestedSidebarDrawerVisibilityProps> = ({
|
||||
label={t("advanced")}
|
||||
onClick={showAdvancedSettings}
|
||||
/>
|
||||
{isHLSGenerationSupported() && (
|
||||
{isHLSGenerationSupported && (
|
||||
<Stack>
|
||||
<RowButtonGroupTitle icon={<ScienceIcon />}>
|
||||
{t("labs")}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user