From 34621dd00fb77484bdcfd7d87c177a3570cb083b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 17:58:40 +0530 Subject: [PATCH 01/18] notes --- .../Collections/CollectionHeader.tsx | 4 +- web/packages/media/collection.ts | 54 ++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/components/Collections/CollectionHeader.tsx b/web/apps/photos/src/components/Collections/CollectionHeader.tsx index 456ed16038..aa85534a57 100644 --- a/web/apps/photos/src/components/Collections/CollectionHeader.tsx +++ b/web/apps/photos/src/components/Collections/CollectionHeader.tsx @@ -582,9 +582,9 @@ const EmptyTrashQuickOption: React.FC = ({ onClick }) => ( ); const showDownloadQuickOption = (type: CollectionSummaryType) => + type == "album" || type == "folder" || type == "favorites" || - type == "album" || type == "uncategorized" || type == "hiddenItems" || type == "incomingShareViewer" || @@ -620,10 +620,10 @@ const DownloadQuickOption: React.FC = ({ ); const showShareQuickOption = (type: CollectionSummaryType) => + type == "album" || type == "folder" || (type == "favorites" && /* TODO(FAV): */ settingsSnapshot().isInternalUser) || - type == "album" || type == "outgoingShare" || type == "sharedOnlyViaLink" || type == "archived" || diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index cf078880db..03469265e1 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -6,10 +6,55 @@ import { ItemVisibility } from "ente-media/file-metadata"; // TODO: Audit this file -export type CollectionType = "folder" | "favorites" | "album" | "uncategorized"; +/** + * The type of a collection. + * + * - "album" - A regular "Ente Album" that the user sees in their library. + * + * - "folder" - An Ente Album that is also associated with an OS album on the + * user's mobile device. + * + * A collection of type "folder" is created by the mobile app if there is an + * associated on-device album for the new Ente album being created. + * + * The web/desktop app does not create collections of type "folder", and + * otherwise treats them as aliases for "album". + * + * - "favorites" - A special collection consisting of the items that the user + * has marked as their favorites. + * + * The user can have at most one collection of type "favorites" (enforced at + * remote). This collection is created on demand by the client where the user + * first marks an item as a favorite. The user can choose to share their + * "favorites" with other users, so it is possible for there to be multiple + * collections of type "favorites" present in our local database, however only + * one of those will belong to the logged in user (cf `owner.id`). + * + * - "uncategorized" - A special collection consisting of items that do not + * belong to any other collection. + * + * In the remote schema, each item ({@link EnteFile}) is always associated + * with a collection. The same item may belong to multiple collections (See: + * [Note: Collection File]), but it must belong to at least one collection. + * + * In some scenarios, e.g. when deleting the last collection to which a file + * belongs, the file would thus get orphaned and violate the schema + * invariants. So in such cases, the client which is performing the + * corresponding operation moves the file to the user's special + * "uncategorized" collection, creating it if needed. + * + * Similar to "favorites", the user can have only one "uncategorized" + * collection. However, unlike "favorites", the "uncategorized" collection + * cannot be shared. + */ +export type CollectionType = "album" | "folder" | "favorites" | "uncategorized"; export type CollectionRole = "VIEWER" | "OWNER" | "COLLABORATOR" | "UNKNOWN"; +/** + * Information about the user associated with a collection, either as an owner, + * or as someone with whom the collection has been shared with. + */ export interface CollectionUser { id: number; email: string; @@ -25,6 +70,13 @@ export interface EncryptedCollection { * all collections on an Ente instance (i.e., it is not scoped to a user). */ id: number; + /** + * Information about the user who owns the collection. + * + * Each collection is owned by exactly one user. The owner may optionally + * choose to share it with additional users, granting them varying level of + * privileges. + */ owner: CollectionUser; // collection name was unencrypted in the past, so we need to keep it as optional name?: string; From 191db47d796f1b65ac7c5a4c98b7e481d80a0d34 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 18:22:27 +0530 Subject: [PATCH 02/18] type --- web/packages/media/collection.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index 03469265e1..8d6d0f1bcf 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -49,7 +49,11 @@ import { ItemVisibility } from "ente-media/file-metadata"; */ export type CollectionType = "album" | "folder" | "favorites" | "uncategorized"; -export type CollectionRole = "VIEWER" | "OWNER" | "COLLABORATOR" | "UNKNOWN"; +export type CollectionUserRole = + | "VIEWER" + | "OWNER" + | "COLLABORATOR" + | "UNKNOWN"; /** * Information about the user associated with a collection, either as an owner, @@ -58,7 +62,7 @@ export type CollectionRole = "VIEWER" | "OWNER" | "COLLABORATOR" | "UNKNOWN"; export interface CollectionUser { id: number; email: string; - role: CollectionRole; + role: CollectionUserRole; } export interface EncryptedCollection { From 1f7e74131ba9639c546d92513954b18f5d0a4ee1 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 19:05:37 +0530 Subject: [PATCH 03/18] + --- web/packages/media/collection.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index 8d6d0f1bcf..63552bb6a5 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -49,10 +49,24 @@ import { ItemVisibility } from "ente-media/file-metadata"; */ export type CollectionType = "album" | "folder" | "favorites" | "uncategorized"; +/** + * The privilege level of a participant associated with a collection. + * + * - "VIEWER" - Has read-only access to files in the collection. + * + * - "COLLABORATOR" - Can additionally add files from the collection, and remove + * files that they added from the collection. + * + * - "OWNER" - The owner of the collection. Can remove any file, including those + * added by other users, from the collection. + * + * It is guaranteed that a there will be exactly one participant of type OWNER, + * and their user ID will be the same as the collection `owner.id`. + */ export type CollectionUserRole = | "VIEWER" - | "OWNER" | "COLLABORATOR" + | "OWNER" | "UNKNOWN"; /** From 8bad8b87b11c9f474a578f6b626259c176e0559d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 19:23:37 +0530 Subject: [PATCH 04/18] more context from chat --- web/packages/media/collection.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index 63552bb6a5..745cb63ce7 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -17,6 +17,11 @@ import { ItemVisibility } from "ente-media/file-metadata"; * A collection of type "folder" is created by the mobile app if there is an * associated on-device album for the new Ente album being created. * + * This separation between "album" and "folder" allows different mobile + * clients to push to the same Folder ("Camera", "Screenshots"), not allowing + * for duplicate folders with the same name, while still allowing users to + * create different albums with the same name. + * * The web/desktop app does not create collections of type "folder", and * otherwise treats them as aliases for "album". * @@ -55,7 +60,7 @@ export type CollectionType = "album" | "folder" | "favorites" | "uncategorized"; * - "VIEWER" - Has read-only access to files in the collection. * * - "COLLABORATOR" - Can additionally add files from the collection, and remove - * files that they added from the collection. + * files that they added from the collection (i.e., files they "own"). * * - "OWNER" - The owner of the collection. Can remove any file, including those * added by other users, from the collection. From aadab316f620785ffefc5daac1e5b09fc37458c0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 19:26:06 +0530 Subject: [PATCH 05/18] + --- web/packages/media/collection.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index 745cb63ce7..b2021fa92c 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -79,8 +79,18 @@ export type CollectionUserRole = * or as someone with whom the collection has been shared with. */ export interface CollectionUser { + /** + * The ID of the underlying {@link User} that this {@link CollectionUser} + * stands for. + */ id: number; + /** + * The email of the user. + */ email: string; + /** + * The association / privilege level of the user with the collection. + */ role: CollectionUserRole; } From b7cd55aec3e329a09972e43f041ba660a5b9c95f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 19 May 2025 19:44:29 +0530 Subject: [PATCH 06/18] ctx "OwnerEmail currently is always present for shared collection but missing for owned collection." --- web/packages/media/collection.ts | 13 +++++++++++-- .../new/photos/components/gallery/helpers.ts | 7 ++++--- .../new/photos/components/gallery/reducer.ts | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts index b2021fa92c..5581cac124 100644 --- a/web/packages/media/collection.ts +++ b/web/packages/media/collection.ts @@ -86,12 +86,21 @@ export interface CollectionUser { id: number; /** * The email of the user. + * + * - The email is present for the {@link owner} only for shared collections. + * - The email is present for all {@link sharees}. + * - Remote uses a blank string to indicate absent values. */ - email: string; + email?: string; /** * The association / privilege level of the user with the collection. + * + * - The role is not present blank for the {@link owner}. + * - The role is present, and one of "VIEWER" and "COLLABORATOR" for the + * {@link sharees}. + * - Remote uses a blank string to indicate absent values. */ - role: CollectionUserRole; + role?: CollectionUserRole; } export interface EncryptedCollection { diff --git a/web/packages/new/photos/components/gallery/helpers.ts b/web/packages/new/photos/components/gallery/helpers.ts index fde1b89526..afce9688d9 100644 --- a/web/packages/new/photos/components/gallery/helpers.ts +++ b/web/packages/new/photos/components/gallery/helpers.ts @@ -52,7 +52,7 @@ export const constructUserIDToEmailMap = ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (sharees) { sharees.forEach((item) => { - if (item.id !== user.id) + if (item.id !== user.id && item.email) userIDToEmailMap.set(item.id, item.email); }); } @@ -78,10 +78,11 @@ export const createShareeSuggestionEmails = ( // type for Collection. // // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - return (sharees ?? []).map((sharee) => sharee.email); + return (sharees ?? []).map(({ email }) => email); } }) - .flat(); + .flat() + .filter((e) => e !== undefined); // Add family members. if (familyData) { diff --git a/web/packages/new/photos/components/gallery/reducer.ts b/web/packages/new/photos/components/gallery/reducer.ts index 6881274c0d..891b972cfa 100644 --- a/web/packages/new/photos/components/gallery/reducer.ts +++ b/web/packages/new/photos/components/gallery/reducer.ts @@ -1442,7 +1442,7 @@ const createCollectionSummaries = ( // particular favorite as a prefix to disambiguate this collection // from the user's own favorites. // TODO(FAV): localize - const initial = collection.owner.email.at(0)?.toUpperCase(); + const initial = collection.owner.email?.at(0)?.toUpperCase(); if (initial) { // TODO(FAV): // name = `${initial}'s ${t("favorites")}`; From 465e69b2542be560a325b3fc77b6403249d59f54 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 10:13:12 +0530 Subject: [PATCH 07/18] Whitelist range header --- server/cmd/museum/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 7070b8af61..24b0950176 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -1010,7 +1010,7 @@ func cors() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", c.GetHeader("Origin")) c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, X-Auth-Token, X-Auth-Access-Token, X-Cast-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package, X-Client-Version, Authorization, accept, origin, Cache-Control, X-Requested-With, upgrade-insecure-requests") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, X-Auth-Token, X-Auth-Access-Token, X-Cast-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package, X-Client-Version, Authorization, accept, origin, Cache-Control, X-Requested-With, upgrade-insecure-requests, Range") c.Writer.Header().Set("Access-Control-Expose-Headers", "X-Request-Id") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH, DELETE") c.Writer.Header().Set("Access-Control-Max-Age", "1728000") From 1c3428d89db0f803b8b4730de56881be818cc6f2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 20 May 2025 12:28:07 +0530 Subject: [PATCH 08/18] Avoid stdout max buffer error when converting very large videos --- desktop/src/main/services/ffmpeg-worker.ts | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index cf8155f2cd..420906925a 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -4,6 +4,7 @@ // See [Note: Using Electron APIs in UtilityProcess] about what we can and // cannot import. +import shellescape from "any-shell-escape"; import { expose } from "comlink"; import pathToFfmpeg from "ffmpeg-static"; import { randomBytes } from "node:crypto"; @@ -324,6 +325,20 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( const playlistPath = path.join(outputPathPrefix, "output.m3u8"); const videoPath = path.join(outputPathPrefix, "output.ts"); + // A file into which we'll redirect ffmpeg's stderr. + // + // [Note: ERR_CHILD_PROCESS_STDIO_MAXBUFFER] + // + // For very large videos, the stderr output of ffmpeg may cause the stdio + // max buffer size limits to be exceeded, raising the following error: + // + // RangeError [ERR_CHILD_PROCESS_STDIO_MAXBUFFER]: stderr maxBuffer length exceeded + // + // So instead of capturing the stderr normally, we redirect it to a + // temporary file, and then read it from there to extract the video + // dimensions. + const stderrPath = path.join(outputPathPrefix, "stderr.txt"); + // Generate a cryptographically secure random key (16 bytes). const keyBytes = randomBytes(16); const keyB64 = keyBytes.toString("base64"); @@ -458,7 +473,7 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( playlistPath, ].flat(); - let dimensions: ReturnType; + let dimensions: { width: number; height: number }; let videoSize: number; try { @@ -468,14 +483,17 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( fs.writeFile(keyInfoPath, keyInfo, { encoding: "utf8" }), ]); + // Tack on the redirection after constructing the command. + const commandWithRedirection = `${shellescape(command)} 2>${stderrPath}`; + // Run the ffmpeg command to generate the HLS playlist and segments. // // Note: Depending on the size of the input file, this may take long! - const { stderr: conversionStderr } = await execAsyncWorker(command); + await execAsyncWorker(commandWithRedirection); // Determine the dimensions of the generated video from the stderr // output produced by ffmpeg during the conversion. - dimensions = detectVideoDimensions(conversionStderr); + dimensions = await detectVideoDimensions(stderrPath); // Find the size of the generated video segments by reading the size of // the generated .ts file. @@ -488,6 +506,7 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( throw e; } finally { await Promise.all([ + deletePathIgnoringErrors(stderrPath), deletePathIgnoringErrors(keyInfoPath), deletePathIgnoringErrors(keyPath), deletePathIgnoringErrors(videoPath), @@ -628,7 +647,12 @@ const detectVideoCharacteristics = async (inputFilePath: string) => { * * See: [Note: Parsing CLI output might break on ffmpeg updates]. */ -const detectVideoDimensions = (conversionStderr: string) => { +const detectVideoDimensions = async (stderrPath: string) => { + // Instead of reading the stderr directly off the child_process.exec, we + // wrote it to a file to avoid hitting the max stdio buffer limits. Read it + // from there. + const conversionStderr = await fs.readFile(stderrPath, "utf-8"); + // There is a nicer way to do it - by running `pseudoFFProbeVideo` on the // generated playlist. However, that playlist includes a data URL that // specifies the encryption info, and ffmpeg refuses to read that unless we From 55264445b2504ac348988d8cf17524e46dcfd86b Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 13:59:05 +0530 Subject: [PATCH 09/18] Fix: Switch to original video playback --- mobile/lib/ui/viewer/file/video_widget_native.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index 68653265c7..b84cdc0e3c 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -112,6 +112,7 @@ class _VideoWidgetNativeState extends State _streamSwitchedSubscription = Bus.instance.on().listen((event) { if (event.type != PlayerType.nativeVideoPlayer) return; + _filePath = null; if (event.selectedPreview) { loadPreview(update: true); } else { @@ -133,6 +134,11 @@ class _VideoWidgetNativeState extends State } Future setVideoSource() async { + if (_filePath == null) { + _logger.info('Stop video player, file path is null'); + await _controller?.stop(); + return; + } final videoSource = VideoSource( path: _filePath!, type: VideoSourceType.file, From 43641b0b9e7086f69ea4c1b4e44708defa88d464 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 14:31:54 +0530 Subject: [PATCH 10/18] Add script to validate & create release tag --- auth/scripts/release_tag.sh | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100755 auth/scripts/release_tag.sh diff --git a/auth/scripts/release_tag.sh b/auth/scripts/release_tag.sh new file mode 100755 index 0000000000..fee85d2d74 --- /dev/null +++ b/auth/scripts/release_tag.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +#!/bin/bash + +# Function to display usage +usage() { + echo "Usage: $0 tag" + exit 1 +} + +# Ensure a tag was provided +[[ $# -eq 0 ]] && usage + +# Exit immediately if a command exits with a non-zero status +set -e + +# Go to the project root directory +cd "$(dirname "$0")/.." + +# Get the tag from the command line argument +TAG=$1 + + +# Get the version from the pubspec.yaml file and cut everything after the + +VERSION=$(grep "^version:" pubspec.yaml | awk '{ print $2 }' | cut -d '+' -f 1) + +PREFIX="auth-v" + +# Ensure the tag has the correct prefix +if [[ $TAG != $PREFIX* ]]; then + echo "Invalid tag. tags must start with '$PREFIX'." + exit 1 +fi + +# Ensure the tag version is in the pubspec.yaml file +if [[ $TAG != *$VERSION ]]; then + echo "Invalid tag." + echo "The version $VERSION in pubspec doesn't match the version in tag $TAG" + exit 1 +fi + +## If all checks pass, create the tag +git tag $TAG +echo "Tag $TAG created." + +exit 0 From be00cbaa5127c0fc3957bdbeaadfdd7aa35020e2 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 14:44:53 +0530 Subject: [PATCH 11/18] Add release 4.3.8 to appdata.xml --- auth/linux/packaging/enteauth.appdata.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/auth/linux/packaging/enteauth.appdata.xml b/auth/linux/packaging/enteauth.appdata.xml index b6682a60ce..82549faa00 100644 --- a/auth/linux/packaging/enteauth.appdata.xml +++ b/auth/linux/packaging/enteauth.appdata.xml @@ -18,6 +18,7 @@ + @@ -33,4 +34,4 @@ #ffffff #000000 - \ No newline at end of file + From 300300a8b9200428550725757fca5ed04a3daef2 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 14:47:10 +0530 Subject: [PATCH 12/18] Add script to add tag --- auth/scripts/release_tag.sh | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/auth/scripts/release_tag.sh b/auth/scripts/release_tag.sh index fee85d2d74..fa6bab6f00 100755 --- a/auth/scripts/release_tag.sh +++ b/auth/scripts/release_tag.sh @@ -1,5 +1,3 @@ -#!/bin/sh - #!/bin/bash # Function to display usage @@ -20,6 +18,9 @@ cd "$(dirname "$0")/.." # Get the tag from the command line argument TAG=$1 +# Define the appdata file path - use absolute path to avoid directory navigation issues +PROJECT_ROOT=$(pwd) +APPDATA_FILE="${PROJECT_ROOT}/linux/packaging/enteauth.appdata.xml" # Get the version from the pubspec.yaml file and cut everything after the + VERSION=$(grep "^version:" pubspec.yaml | awk '{ print $2 }' | cut -d '+' -f 1) @@ -39,8 +40,34 @@ if [[ $TAG != *$VERSION ]]; then exit 1 fi -## If all checks pass, create the tag +# Extract version number from the tag (remove prefix) +TAG_VERSION=${TAG#$PREFIX} + +# Check if this version is already in the releases section of the appdata.xml file +if ! grep -q "" + + # Use a more reliable approach with awk instead of sed for cross-platform compatibility + echo "Creating temporary file with updated content..." + awk '//{print $0; print " "; next}1' "$APPDATA_FILE" > "${APPDATA_FILE}.tmp" + mv "${APPDATA_FILE}.tmp" "$APPDATA_FILE" + + echo "Added release entry for version $TAG_VERSION with date $TODAY" + + # Stage and commit the updated appdata.xml file + git add "$APPDATA_FILE" + git commit -m "Add release $TAG_VERSION to appdata.xml" + echo "Committed appdata.xml changes for version $TAG_VERSION" +fi + +# If all checks pass, create the tag git tag $TAG echo "Tag $TAG created." -exit 0 +exit 0 \ No newline at end of file From 2d739ef4dec8f9b7882e66bc20d807251fc196a0 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 14:47:30 +0530 Subject: [PATCH 13/18] [auth] Bump version 4.3.8 --- auth/pubspec.lock | 90 +++++++++++++++++++++++------------------------ auth/pubspec.yaml | 2 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/auth/pubspec.lock b/auth/pubspec.lock index 1070e3ba96..fa632892e2 100644 --- a/auth/pubspec.lock +++ b/auth/pubspec.lock @@ -5,15 +5,15 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "76.0.0" + version: "72.0.0" _macros: dependency: transitive description: dart source: sdk - version: "0.3.3" + version: "0.3.2" adaptive_theme: dependency: "direct main" description: @@ -26,10 +26,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.7.0" ansicolor: dependency: transitive description: @@ -90,10 +90,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" auto_size_text: dependency: "direct main" description: @@ -130,10 +130,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" build: dependency: transitive description: @@ -202,10 +202,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -234,10 +234,10 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" code_builder: dependency: transitive description: @@ -250,10 +250,10 @@ packages: dependency: "direct main" description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.18.0" confetti: dependency: "direct main" description: @@ -435,10 +435,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" ffi: dependency: "direct main" description: @@ -944,18 +944,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -1024,18 +1024,18 @@ packages: dependency: transitive description: name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" url: "https://pub.dev" source: hosted - version: "0.1.3-main.0" + version: "0.1.2-main.4" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -1056,10 +1056,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mime: dependency: transitive description: @@ -1168,10 +1168,10 @@ packages: dependency: "direct main" description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -1472,7 +1472,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" sodium: dependency: transitive description: @@ -1509,10 +1509,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" sprintf: dependency: transitive description: @@ -1566,10 +1566,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.11.1" steam_totp: dependency: "direct main" description: @@ -1590,10 +1590,10 @@ packages: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1606,10 +1606,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.2.0" styled_text: dependency: "direct main" description: @@ -1630,18 +1630,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.2" timezone: dependency: transitive description: @@ -1806,10 +1806,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "14.2.5" watcher: dependency: transitive description: @@ -1899,5 +1899,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.7.0-0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.24.0" diff --git a/auth/pubspec.yaml b/auth/pubspec.yaml index cf2d97c7ec..b4027096be 100644 --- a/auth/pubspec.yaml +++ b/auth/pubspec.yaml @@ -1,7 +1,7 @@ name: ente_auth description: ente two-factor authenticator -version: 4.3.6+437 +version: 4.3.8+438 publish_to: none environment: From a52a3e5e57ec5195824c84b62f530964421d3655 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 14:54:17 +0530 Subject: [PATCH 14/18] Remove unused variable --- auth/scripts/release_tag.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/auth/scripts/release_tag.sh b/auth/scripts/release_tag.sh index fa6bab6f00..f35c89ab4d 100755 --- a/auth/scripts/release_tag.sh +++ b/auth/scripts/release_tag.sh @@ -50,9 +50,6 @@ if ! grep -q "" - # Use a more reliable approach with awk instead of sed for cross-platform compatibility echo "Creating temporary file with updated content..." awk '//{print $0; print " "; next}1' "$APPDATA_FILE" > "${APPDATA_FILE}.tmp" From 013389c696dbda42704c72ae2f26077caa7c15f2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 20 May 2025 15:57:41 +0530 Subject: [PATCH 15/18] Fix regex for Windows --- desktop/src/main/services/ffmpeg-worker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index 420906925a..a5ccf503b9 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -544,10 +544,10 @@ const deletePathIgnoringErrors = async (tempFilePath: string) => { * * Stream #0:1[0x2](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 480x270 [SAR 1:1 DAR 16:9], 539 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default) */ -const videoStreamLineRegex = /Stream #.+: Video:(.+)\n/; +const videoStreamLineRegex = /Stream #.+: Video:(.+)$/; /** {@link videoStreamLineRegex}, but global. */ -const videoStreamLinesRegex = /Stream #.+: Video:(.+)\n/g; +const videoStreamLinesRegex = /Stream #.+: Video:(.+)$/g; /** * A regex that matches " kb/s" preceded by a space. See From a062c1ccc342ef7844e47de75d902ea3ac7ec4a2 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 20 May 2025 16:35:22 +0530 Subject: [PATCH 16/18] Fix err handling --- server/pkg/controller/filedata/video.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/pkg/controller/filedata/video.go b/server/pkg/controller/filedata/video.go index ee48c268db..8fba680e44 100644 --- a/server/pkg/controller/filedata/video.go +++ b/server/pkg/controller/filedata/video.go @@ -29,8 +29,7 @@ func (c *Controller) InsertVideoPreview(ctx *gin.Context, req *filedata.VidPrevi if sizeErr := c.verifySize(bucketID, fileObjectKey, req.ObjectSize); sizeErr != nil { return stacktrace.Propagate(sizeErr, "failed to validate size") } - // Start a goroutine to handle the upload and insert operations - //go func() { + obj := filedata.S3FileMetadata{ Version: *req.Version, EncryptedData: req.Playlist, @@ -59,9 +58,9 @@ func (c *Controller) InsertVideoPreview(ctx *gin.Context, req *filedata.VidPrevi dbInsertErr := c.Repo.InsertOrUpdatePreviewData(context.Background(), row, fileObjectKey) if dbInsertErr != nil { logger.WithError(dbInsertErr).Error("insert or update failed") - return nil + return stacktrace.Propagate(dbInsertErr, "failed to insert or update preview data") } - //}() + return nil } From 7a10f4c145f29deb6c5e98d7801755db42616ddf Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 20 May 2025 19:58:10 +0530 Subject: [PATCH 17/18] Note results of tests and add extra checks --- desktop/src/main/services/ffmpeg-worker.ts | 21 +++++++++++++++++++ web/packages/gallery/services/ffmpeg/index.ts | 7 ++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index a5ccf503b9..aab130645f 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -357,6 +357,18 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( // - the first line specifies the key URI that is written into the playlist. // - the second line specifies the path to the local file system file from // where ffmpeg should read the key. + // + // [Note: ffmpeg newlines] + // + // Tested on Windows that ffmpeg recognizes these lines correctly. In + // general, ffmpeg tends to expect input and write output the Unix way (\n), + // even when we're running on Windows. + // + // - The ffmetadata and the HLS playlist file generated by ffmpeg uses \n + // separators, even on Windows. + // - The HLS key info file, expected as an input by ffmpeg, works fine when + // \n separated even on Windows. + // const keyInfo = [keyURI, keyPath].join("\n"); // Overview: @@ -491,6 +503,15 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( // Note: Depending on the size of the input file, this may take long! await execAsyncWorker(commandWithRedirection); + // While ffmpeg uses \n as the line separator in the generated playlist + // file on Windows too, add an extra safety check that should fail the + // HLS generation if this doesn't hold. See: [Note: ffmpeg newlines]. + if (process.platform == "win32") { + const playlistText = await fs.readFile(playlistPath, "utf-8"); + if (playlistText.includes("\r\n")) + throw new Error("Unexpected Windows newlines in playlist"); + } + // Determine the dimensions of the generated video from the stderr // output produced by ffmpeg during the conversion. dimensions = await detectVideoDimensions(stderrPath); diff --git a/web/packages/gallery/services/ffmpeg/index.ts b/web/packages/gallery/services/ffmpeg/index.ts index b31f92b80d..8c7817ee4e 100644 --- a/web/packages/gallery/services/ffmpeg/index.ts +++ b/web/packages/gallery/services/ffmpeg/index.ts @@ -184,8 +184,13 @@ const parseFFmpegExtractedMetadata = (ffmpegOutput: Uint8Array) => { // with comments and newlines. // // https://ffmpeg.org/ffmpeg-formats.html#Metadata-2 + // + // On Windows, while I couldn't find it documented anywhere, the generated + // ffmetadata file uses Unix line separators ("\n"). But for the sake of + // extra (albeit possibly unnecessary) safety, handle both \r\n and \n + // separators in the split. See: [Note: ffmpeg newlines] - const lines = new TextDecoder().decode(ffmpegOutput).split("\n"); + const lines = new TextDecoder().decode(ffmpegOutput).split(/\r?\n/); const isPair = (xs: string[]): xs is [string, string] => xs.length == 2; const kvPairs = lines.map((property) => property.split("=")).filter(isPair); From 914893eae6b83021c17637326ff29997ab8ce795 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 20 May 2025 19:59:35 +0530 Subject: [PATCH 18/18] Fix --- desktop/src/main/services/ffmpeg-worker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index aab130645f..f14f3fc53f 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -565,10 +565,10 @@ const deletePathIgnoringErrors = async (tempFilePath: string) => { * * Stream #0:1[0x2](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 480x270 [SAR 1:1 DAR 16:9], 539 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default) */ -const videoStreamLineRegex = /Stream #.+: Video:(.+)$/; +const videoStreamLineRegex = /Stream #.+: Video:(.+)\r?\n/; /** {@link videoStreamLineRegex}, but global. */ -const videoStreamLinesRegex = /Stream #.+: Video:(.+)$/g; +const videoStreamLinesRegex = /Stream #.+: Video:(.+)\r?\n/g; /** * A regex that matches " kb/s" preceded by a space. See