From e8e264d60ee47ab6d59b617d901dd39fc71cceba Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 21 Feb 2024 13:24:26 +0530 Subject: [PATCH 1/3] [ios build files] Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- ios/Podfile.lock | 6 ++++++ ios/Runner.xcodeproj/project.pbxproj | 2 ++ 2 files changed, 8 insertions(+) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e7046d210..8d84abb91 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,6 +1,8 @@ PODS: - background_fetch (1.2.1): - Flutter + - battery_info (0.0.1): + - Flutter - connectivity_plus (0.0.1): - Flutter - ReachabilitySwift @@ -213,6 +215,7 @@ PODS: DEPENDENCIES: - background_fetch (from `.symlinks/plugins/background_fetch/ios`) + - battery_info (from `.symlinks/plugins/battery_info/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_saver (from `.symlinks/plugins/file_saver/ios`) @@ -286,6 +289,8 @@ SPEC REPOS: EXTERNAL SOURCES: background_fetch: :path: ".symlinks/plugins/background_fetch/ios" + battery_info: + :path: ".symlinks/plugins/battery_info/ios" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: @@ -377,6 +382,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: background_fetch: 896944864b038d2837fc750d470e9841e1e6a363 + battery_info: 09f5c9ee65394f2291c8c6227bedff345b8a730c connectivity_plus: 53efb943fc2882c8512d84c45707bcabc4c36076 device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ea4cd3588..6813056ec 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -276,6 +276,7 @@ "${BUILT_PRODUCTS_DIR}/SentryPrivate/SentryPrivate.framework", "${BUILT_PRODUCTS_DIR}/Toast/Toast.framework", "${BUILT_PRODUCTS_DIR}/background_fetch/background_fetch.framework", + "${BUILT_PRODUCTS_DIR}/battery_info/battery_info.framework", "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", "${BUILT_PRODUCTS_DIR}/file_saver/file_saver.framework", @@ -357,6 +358,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SentryPrivate.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/background_fetch.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/battery_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_saver.framework", From a023a5764d6d060187cda7e584adf2b8b249fba7 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 21 Feb 2024 13:29:47 +0530 Subject: [PATCH 2/3] Add support for uploading vid without thumbnail Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/core/constants.dart | 28 +++++++++++++++++++++ lib/models/metadata/file_magic.dart | 10 ++++++++ lib/utils/file_uploader.dart | 39 ++++++++++++++++++++++------- lib/utils/file_uploader_util.dart | 8 ++++++ 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 5c70e218f..bc59fccc0 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -68,3 +68,31 @@ const galleryGridSpacing = 2.0; const searchSectionLimit = 7; bool isInternalUser = false; + +const blackThumbnailBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB' + + 'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ' + + 'EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARC' + + 'ACWASwDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF' + + 'BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk' + + '6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztL' + + 'W2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAA' + + 'AAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVY' + + 'nLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImK' + + 'kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oAD' + + 'AMBAAIRAxEAPwD/AD/6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + + 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + + 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAC' + + 'gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + + 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + + 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + + 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + + 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + + 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' + + 'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + + 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + + 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + + 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAK' + + 'ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' + + 'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + + 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + + 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD/9k='; diff --git a/lib/models/metadata/file_magic.dart b/lib/models/metadata/file_magic.dart index ca08f95f8..d50dc0dd8 100644 --- a/lib/models/metadata/file_magic.dart +++ b/lib/models/metadata/file_magic.dart @@ -11,6 +11,7 @@ const heightKey = 'h'; const latKey = "lat"; const longKey = "long"; const motionVideoIndexKey = "mvi"; +const noThumbKey = "noThumb"; class MagicMetadata { // 0 -> visible @@ -47,6 +48,13 @@ class PubMagicMetadata { // photo int? mvi; + // if true, then the thumbnail is not available + // Note: desktop/web sets hasStaticThumbnail in the file metadata. + // As we don't want to support updating the og file metadata (yet), adding + // this new field to the pub metadata. For static thumbnail, all thumbnails + // should have exact same hash with should match the constant `blackThumbnailBase64` + bool? noThumb; + PubMagicMetadata({ this.editedTime, this.editedName, @@ -57,6 +65,7 @@ class PubMagicMetadata { this.lat, this.long, this.mvi, + this.noThumb, }); factory PubMagicMetadata.fromEncodedJson(String encodedJson) => @@ -77,6 +86,7 @@ class PubMagicMetadata { lat: map[latKey], long: map[longKey], mvi: map[motionVideoIndexKey], + noThumb: map[noThumbKey], ); } } diff --git a/lib/utils/file_uploader.dart b/lib/utils/file_uploader.dart index 653b5076b..c0dc3ee98 100644 --- a/lib/utils/file_uploader.dart +++ b/lib/utils/file_uploader.dart @@ -10,6 +10,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; import 'package:photos/core/configuration.dart'; +import "package:photos/core/constants.dart"; import 'package:photos/core/errors.dart'; import 'package:photos/core/event_bus.dart'; import 'package:photos/core/network/network.dart'; @@ -69,6 +70,8 @@ class FileUploader { late ProcessType _processType; late bool _isBackground; late SharedPreferences _prefs; + Uint8List? _staticThumbnailData; + // _hasInitiatedForceUpload is used to track if user attempted force upload // where files are uploaded directly (without adding them to DB). In such // cases, we don't want to clear the stale upload files. See #removeStaleFiles @@ -431,7 +434,13 @@ class FileUploader { encryptedFilePath, key: key, ); - final thumbnailData = mediaUploadData.thumbnail; + late final Uint8List? thumbnailData; + if (mediaUploadData.thumbnail == null && + file.fileType == FileType.video) { + thumbnailData = await getStaticThumbnailData(); + } else { + thumbnailData = mediaUploadData.thumbnail; + } final EncryptionResult encryptedThumbnailData = await CryptoUtil.encryptChaCha( @@ -493,17 +502,21 @@ class FileUploader { CryptoUtil.bin2base64(encryptedFileKeyData.encryptedData!); final keyDecryptionNonce = CryptoUtil.bin2base64(encryptedFileKeyData.nonce!); + final Map pubMetadata = {}; MetadataRequest? pubMetadataRequest; if ((mediaUploadData.height ?? 0) != 0 && (mediaUploadData.width ?? 0) != 0) { - final pubMetadata = { - heightKey: mediaUploadData.height, - widthKey: mediaUploadData.width, - }; - if (mediaUploadData.motionPhotoStartIndex != null) { - pubMetadata[motionVideoIndexKey] = - mediaUploadData.motionPhotoStartIndex; - } + pubMetadata[heightKey] = mediaUploadData.height; + pubMetadata[widthKey] = mediaUploadData.width; + } + if (mediaUploadData.motionPhotoStartIndex != null) { + pubMetadata[motionVideoIndexKey] = + mediaUploadData.motionPhotoStartIndex; + } + if (mediaUploadData.thumbnail == null) { + pubMetadata[noThumbKey] = true; + } + if (pubMetadata.isNotEmpty) { pubMetadataRequest = await getPubMetadataRequest( file, pubMetadata, @@ -1070,6 +1083,14 @@ class FileUploader { } } + Future getStaticThumbnailData() async { + if (_staticThumbnailData != null) { + return _staticThumbnailData!; + } + _staticThumbnailData = base64Decode(blackThumbnailBase64); + return _staticThumbnailData; + } + Future _pollBackgroundUploadStatus() async { final blockedUploads = _queue.entries .where((e) => e.value.status == UploadStatus.inBackground) diff --git a/lib/utils/file_uploader_util.dart b/lib/utils/file_uploader_util.dart index f877747aa..1455ee0e9 100644 --- a/lib/utils/file_uploader_util.dart +++ b/lib/utils/file_uploader_util.dart @@ -208,6 +208,10 @@ Future _getThumbnailForUpload( quality: thumbnailQuality, ); if (thumbnailData == null) { + // allow videos to be uploaded without thumbnails + if (asset.type == AssetType.video) { + return null; + } throw InvalidFileError( "no thumbnail : ${file.fileType} ${file.tag}", InvalidReason.thumbnailMissing, @@ -227,6 +231,10 @@ Future _getThumbnailForUpload( final String errMessage = "thumbErr for ${file.fileType}, ${extension(file.displayName)} ${file.tag}"; _logger.warning(errMessage, e); + // allow videos to be uploaded without thumbnails + if (asset.type == AssetType.video) { + return null; + } throw InvalidFileError(errMessage, InvalidReason.thumbnailMissing); } } From 28e841881a006e056131c766f068bbd1aaf53560 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 21 Feb 2024 13:32:19 +0530 Subject: [PATCH 3/3] Refactor --- lib/utils/file_uploader.dart | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/utils/file_uploader.dart b/lib/utils/file_uploader.dart index c0dc3ee98..5d65f3563 100644 --- a/lib/utils/file_uploader.dart +++ b/lib/utils/file_uploader.dart @@ -70,7 +70,6 @@ class FileUploader { late ProcessType _processType; late bool _isBackground; late SharedPreferences _prefs; - Uint8List? _staticThumbnailData; // _hasInitiatedForceUpload is used to track if user attempted force upload // where files are uploaded directly (without adding them to DB). In such @@ -437,7 +436,7 @@ class FileUploader { late final Uint8List? thumbnailData; if (mediaUploadData.thumbnail == null && file.fileType == FileType.video) { - thumbnailData = await getStaticThumbnailData(); + thumbnailData = base64Decode(blackThumbnailBase64); } else { thumbnailData = mediaUploadData.thumbnail; } @@ -1083,14 +1082,6 @@ class FileUploader { } } - Future getStaticThumbnailData() async { - if (_staticThumbnailData != null) { - return _staticThumbnailData!; - } - _staticThumbnailData = base64Decode(blackThumbnailBase64); - return _staticThumbnailData; - } - Future _pollBackgroundUploadStatus() async { final blockedUploads = _queue.entries .where((e) => e.value.status == UploadStatus.inBackground)