Explorar o código

Allow video upload without thumbnail (#1737)

Neeraj Gupta hai 1 ano
pai
achega
abeb2484b8

+ 28 - 0
lib/core/constants.dart

@@ -68,3 +68,31 @@ const galleryGridSpacing = 2.0;
 const searchSectionLimit = 7;
 const searchSectionLimit = 7;
 
 
 bool isInternalUser = false;
 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=';

+ 10 - 0
lib/models/metadata/file_magic.dart

@@ -11,6 +11,7 @@ const heightKey = 'h';
 const latKey = "lat";
 const latKey = "lat";
 const longKey = "long";
 const longKey = "long";
 const motionVideoIndexKey = "mvi";
 const motionVideoIndexKey = "mvi";
+const noThumbKey = "noThumb";
 
 
 class MagicMetadata {
 class MagicMetadata {
   // 0 -> visible
   // 0 -> visible
@@ -47,6 +48,13 @@ class PubMagicMetadata {
   // photo
   // photo
   int? mvi;
   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({
   PubMagicMetadata({
     this.editedTime,
     this.editedTime,
     this.editedName,
     this.editedName,
@@ -57,6 +65,7 @@ class PubMagicMetadata {
     this.lat,
     this.lat,
     this.long,
     this.long,
     this.mvi,
     this.mvi,
+    this.noThumb,
   });
   });
 
 
   factory PubMagicMetadata.fromEncodedJson(String encodedJson) =>
   factory PubMagicMetadata.fromEncodedJson(String encodedJson) =>
@@ -77,6 +86,7 @@ class PubMagicMetadata {
       lat: map[latKey],
       lat: map[latKey],
       long: map[longKey],
       long: map[longKey],
       mvi: map[motionVideoIndexKey],
       mvi: map[motionVideoIndexKey],
+      noThumb: map[noThumbKey],
     );
     );
   }
   }
 }
 }

+ 20 - 9
lib/utils/file_uploader.dart

@@ -71,6 +71,7 @@ class FileUploader {
   late ProcessType _processType;
   late ProcessType _processType;
   late bool _isBackground;
   late bool _isBackground;
   late SharedPreferences _prefs;
   late SharedPreferences _prefs;
+
   // _hasInitiatedForceUpload is used to track if user attempted force upload
   // _hasInitiatedForceUpload is used to track if user attempted force upload
   // where files are uploaded directly (without adding them to DB). In such
   // 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
   // cases, we don't want to clear the stale upload files. See #removeStaleFiles
@@ -457,7 +458,13 @@ class FileUploader {
         encryptedFilePath,
         encryptedFilePath,
         key: key,
         key: key,
       );
       );
-      final thumbnailData = mediaUploadData.thumbnail;
+      late final Uint8List? thumbnailData;
+      if (mediaUploadData.thumbnail == null &&
+          file.fileType == FileType.video) {
+        thumbnailData = base64Decode(blackThumbnailBase64);
+      } else {
+        thumbnailData = mediaUploadData.thumbnail;
+      }
 
 
       final EncryptionResult encryptedThumbnailData =
       final EncryptionResult encryptedThumbnailData =
           await CryptoUtil.encryptChaCha(
           await CryptoUtil.encryptChaCha(
@@ -519,17 +526,21 @@ class FileUploader {
             CryptoUtil.bin2base64(encryptedFileKeyData.encryptedData!);
             CryptoUtil.bin2base64(encryptedFileKeyData.encryptedData!);
         final keyDecryptionNonce =
         final keyDecryptionNonce =
             CryptoUtil.bin2base64(encryptedFileKeyData.nonce!);
             CryptoUtil.bin2base64(encryptedFileKeyData.nonce!);
+        final Map<String, dynamic> pubMetadata = {};
         MetadataRequest? pubMetadataRequest;
         MetadataRequest? pubMetadataRequest;
         if ((mediaUploadData.height ?? 0) != 0 &&
         if ((mediaUploadData.height ?? 0) != 0 &&
             (mediaUploadData.width ?? 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(
           pubMetadataRequest = await getPubMetadataRequest(
             file,
             file,
             pubMetadata,
             pubMetadata,

+ 8 - 0
lib/utils/file_uploader_util.dart

@@ -208,6 +208,10 @@ Future<Uint8List?> _getThumbnailForUpload(
       quality: thumbnailQuality,
       quality: thumbnailQuality,
     );
     );
     if (thumbnailData == null) {
     if (thumbnailData == null) {
+      // allow videos to be uploaded without thumbnails
+      if (asset.type == AssetType.video) {
+        return null;
+      }
       throw InvalidFileError(
       throw InvalidFileError(
         "no thumbnail : ${file.fileType} ${file.tag}",
         "no thumbnail : ${file.fileType} ${file.tag}",
         InvalidReason.thumbnailMissing,
         InvalidReason.thumbnailMissing,
@@ -227,6 +231,10 @@ Future<Uint8List?> _getThumbnailForUpload(
     final String errMessage =
     final String errMessage =
         "thumbErr for ${file.fileType}, ${extension(file.displayName)} ${file.tag}";
         "thumbErr for ${file.fileType}, ${extension(file.displayName)} ${file.tag}";
     _logger.warning(errMessage, e);
     _logger.warning(errMessage, e);
+    // allow videos to be uploaded without thumbnails
+    if (asset.type == AssetType.video) {
+      return null;
+    }
     throw InvalidFileError(errMessage, InvalidReason.thumbnailMissing);
     throw InvalidFileError(errMessage, InvalidReason.thumbnailMissing);
   }
   }
 }
 }