react-native-compressor 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +40 -15
  2. package/android/build.gradle +8 -0
  3. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +527 -0
  4. package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +31 -0
  5. package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +157 -0
  6. package/android/src/main/java/com/reactnativecompressor/CompressorPackage.kt +34 -0
  7. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.kt +199 -0
  8. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressorOptions.kt +57 -0
  9. package/android/src/main/java/com/reactnativecompressor/Image/ImageMain.kt +31 -0
  10. package/android/src/main/java/com/reactnativecompressor/Image/ImageSize.kt +3 -0
  11. package/android/src/main/java/com/reactnativecompressor/Utils/Downloader.kt +119 -0
  12. package/android/src/main/java/com/reactnativecompressor/Utils/EventEmitterHandler.kt +66 -0
  13. package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.kt +61 -0
  14. package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.kt +177 -0
  15. package/android/src/main/java/com/reactnativecompressor/Utils/Uploader.kt +117 -0
  16. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +162 -0
  17. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt +63 -0
  18. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt +125 -0
  19. package/android/src/main/java/com/reactnativecompressor/Video/VideoMain.kt +86 -0
  20. package/android/src/newarch/CompressorSpec.kt +5 -0
  21. package/android/src/oldarch/CompressorSpec.kt +32 -0
  22. package/ios/Audio/AudioMain.swift +115 -0
  23. package/ios/Compressor-Bridging-Header.h +1 -2
  24. package/ios/Compressor.h +0 -8
  25. package/ios/Compressor.mm +28 -389
  26. package/ios/CompressorManager.swift +96 -0
  27. package/ios/Image/ImageCompressor.swift +354 -0
  28. package/ios/Image/ImageCompressorOptions.swift +93 -0
  29. package/ios/Image/ImageMain.swift +27 -0
  30. package/ios/Utils/Downloader.swift +157 -0
  31. package/ios/Utils/EventEmitterHandler.swift +54 -0
  32. package/ios/Utils/MediaCache.swift +48 -0
  33. package/ios/Utils/Uploader.swift +99 -0
  34. package/ios/Utils/Utils.swift +110 -0
  35. package/ios/Video/{VideoCompressor.swift → VideoMain.swift} +168 -147
  36. package/lib/commonjs/Image/index.js +1 -1
  37. package/lib/commonjs/Image/index.js.map +1 -1
  38. package/lib/commonjs/Main.js +1 -8
  39. package/lib/commonjs/Main.js.map +1 -1
  40. package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
  41. package/lib/commonjs/Video/index.js +4 -33
  42. package/lib/commonjs/Video/index.js.map +1 -1
  43. package/lib/commonjs/expo-plugin/compressor.js.map +1 -1
  44. package/lib/commonjs/index.js +11 -6
  45. package/lib/commonjs/index.js.map +1 -1
  46. package/lib/commonjs/utils/Downloader.js +38 -0
  47. package/lib/commonjs/utils/Downloader.js.map +1 -0
  48. package/lib/commonjs/utils/Uploader.js +40 -0
  49. package/lib/commonjs/utils/Uploader.js.map +1 -0
  50. package/lib/commonjs/utils/index.js +35 -0
  51. package/lib/commonjs/utils/index.js.map +1 -1
  52. package/lib/module/Image/index.js +1 -1
  53. package/lib/module/Image/index.js.map +1 -1
  54. package/lib/module/Main.js +1 -7
  55. package/lib/module/Main.js.map +1 -1
  56. package/lib/module/Spec/NativeCompressor.js.map +1 -1
  57. package/lib/module/Video/index.js +5 -33
  58. package/lib/module/Video/index.js.map +1 -1
  59. package/lib/module/expo-plugin/compressor.js.map +1 -1
  60. package/lib/module/index.js +6 -6
  61. package/lib/module/index.js.map +1 -1
  62. package/lib/module/utils/Downloader.js +31 -0
  63. package/lib/module/utils/Downloader.js.map +1 -0
  64. package/lib/module/utils/Uploader.js +33 -0
  65. package/lib/module/utils/Uploader.js.map +1 -0
  66. package/lib/module/utils/index.js +2 -0
  67. package/lib/module/utils/index.js.map +1 -1
  68. package/lib/typescript/Image/index.d.ts +4 -0
  69. package/lib/typescript/Image/index.d.ts.map +1 -1
  70. package/lib/typescript/Main.d.ts +1 -2
  71. package/lib/typescript/Main.d.ts.map +1 -1
  72. package/lib/typescript/Spec/NativeCompressor.d.ts +8 -2
  73. package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
  74. package/lib/typescript/Video/index.d.ts +4 -28
  75. package/lib/typescript/Video/index.d.ts.map +1 -1
  76. package/lib/typescript/index.d.ts +5 -4
  77. package/lib/typescript/index.d.ts.map +1 -1
  78. package/lib/typescript/utils/Downloader.d.ts +2 -0
  79. package/lib/typescript/utils/Downloader.d.ts.map +1 -0
  80. package/lib/typescript/utils/Uploader.d.ts +28 -0
  81. package/lib/typescript/utils/Uploader.d.ts.map +1 -0
  82. package/lib/typescript/utils/index.d.ts +2 -1
  83. package/lib/typescript/utils/index.d.ts.map +1 -1
  84. package/package.json +6 -4
  85. package/src/Image/index.tsx +5 -1
  86. package/src/Main.tsx +1 -15
  87. package/src/Spec/NativeCompressor.ts +14 -2
  88. package/src/Video/index.tsx +11 -84
  89. package/src/expo-plugin/compressor.ts +1 -1
  90. package/src/index.tsx +6 -3
  91. package/src/utils/Downloader.tsx +38 -0
  92. package/src/utils/Uploader.tsx +78 -0
  93. package/src/utils/index.tsx +2 -0
  94. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.java +0 -605
  95. package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +0 -220
  96. package/android/src/main/java/com/reactnativecompressor/CompressorPackage.java +0 -58
  97. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +0 -257
  98. package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +0 -69
  99. package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageSize.java +0 -13
  100. package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploadHelper.java +0 -39
  101. package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploader.java +0 -129
  102. package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +0 -65
  103. package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java +0 -210
  104. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +0 -272
  105. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression/AutoVideoCompression.java +0 -87
  106. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.java +0 -182
  107. package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +0 -112
  108. package/android/src/newarch/CompressorSpec.java +0 -9
  109. package/android/src/newarch/VideoCompressorSpec.java +0 -9
  110. package/android/src/oldarch/CompressorSpec.java +0 -34
  111. package/android/src/oldarch/VideoCompressorSpec.java +0 -26
  112. package/ios/Image/ImageCompressor.h +0 -22
  113. package/ios/Image/ImageCompressor.m +0 -540
  114. package/ios/Image/ImageCompressorOptions.h +0 -28
  115. package/ios/Image/ImageCompressorOptions.m +0 -97
  116. package/ios/Utils/Downloader.h +0 -16
  117. package/ios/Utils/Downloader.m +0 -150
  118. package/ios/Utils/MediaCache.h +0 -11
  119. package/ios/Utils/MediaCache.m +0 -51
  120. package/ios/Video/VideoCompressor.h +0 -5
  121. package/ios/Video/VideoCompressor.m +0 -1
  122. package/lib/commonjs/Spec/NativeVideoCompressor.js +0 -10
  123. package/lib/commonjs/Spec/NativeVideoCompressor.js.map +0 -1
  124. package/lib/module/Spec/NativeVideoCompressor.js +0 -3
  125. package/lib/module/Spec/NativeVideoCompressor.js.map +0 -1
  126. package/lib/typescript/Spec/NativeVideoCompressor.d.ts +0 -13
  127. package/lib/typescript/Spec/NativeVideoCompressor.d.ts.map +0 -1
  128. package/src/Spec/NativeVideoCompressor.ts +0 -14
@@ -0,0 +1,61 @@
1
+ package com.reactnativecompressor.Utils
2
+
3
+ import android.util.Log
4
+ import java.io.File
5
+
6
+ object MediaCache {
7
+ private const val TAG = "MediaCache"
8
+ private val completedImagePaths: MutableList<String> = ArrayList()
9
+ fun addCompletedImagePath(imagePath: String?) {
10
+ if (imagePath != null) {
11
+ // Your code to add the imagePath to a list or perform other actions if needed.
12
+ completedImagePaths.add(imagePath)
13
+ Log.d(TAG, "Successfully added image path: $imagePath")
14
+ }
15
+ }
16
+
17
+ @JvmStatic
18
+ fun removeCompletedImagePath(imagePath: String?) {
19
+ var imagePath = imagePath
20
+ if (imagePath != null) {
21
+ if (completedImagePaths.contains(imagePath)) {
22
+ // Image path exists in the list, so remove it
23
+ completedImagePaths.remove(imagePath)
24
+ if (imagePath.startsWith("file://")) {
25
+ imagePath = imagePath.substring(7) // Remove "file://"
26
+ }
27
+
28
+ // Remove the image file
29
+ val file = File(imagePath)
30
+ if (file.exists()) {
31
+ if (file.delete()) {
32
+ Log.d(TAG, "Successfully deleted image file: $imagePath")
33
+ } else {
34
+ Log.d(TAG, "Failed to delete image file: $imagePath")
35
+ }
36
+ } else {
37
+ Log.d(TAG, "Image file not found: $imagePath")
38
+ }
39
+ } else {
40
+ Log.d(TAG, "Image path not found in the completedImagePaths list: $imagePath")
41
+ }
42
+ }
43
+ }
44
+
45
+ fun cleanupCache() {
46
+ // Iterate through the list of completed image paths and delete the corresponding files
47
+ for (imagePath in completedImagePaths) {
48
+ val file = File(imagePath)
49
+ if (file.exists()) {
50
+ if (file.delete()) {
51
+ Log.d(TAG, "Successfully deleted image file during cache cleanup: $imagePath")
52
+ } else {
53
+ Log.d(TAG, "Failed to delete image file during cache cleanup: $imagePath")
54
+ }
55
+ } else {
56
+ Log.d(TAG, "Image file not found during cache cleanup: $imagePath")
57
+ }
58
+ }
59
+ completedImagePaths.clear()
60
+ }
61
+ }
@@ -0,0 +1,177 @@
1
+ package com.reactnativecompressor.Utils
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.ContentUris
5
+ import android.content.Context
6
+ import android.database.Cursor
7
+ import android.net.Uri
8
+ import android.os.Build
9
+ import android.os.Environment
10
+ import android.provider.DocumentsContract
11
+ import android.provider.MediaStore
12
+ import androidx.loader.content.CursorLoader
13
+
14
+ object RealPathUtil {
15
+ fun getRealPath(context: Context, fileUri: Uri): String? {
16
+ val realPath: String?
17
+ // SDK < API11
18
+ realPath = if (Build.VERSION.SDK_INT < 11) {
19
+ getRealPathFromURI_BelowAPI11(context, fileUri)
20
+ } else if (Build.VERSION.SDK_INT < 19) {
21
+ getRealPathFromURI_API11to18(context, fileUri)
22
+ } else {
23
+ getRealPathFromURI_API19(context, fileUri)
24
+ }
25
+ return realPath
26
+ }
27
+
28
+ @SuppressLint("NewApi")
29
+ fun getRealPathFromURI_API11to18(context: Context?, contentUri: Uri?): String? {
30
+ val proj = arrayOf(MediaStore.Images.Media.DATA)
31
+ var result: String? = null
32
+ val cursorLoader = CursorLoader(context!!, contentUri!!, proj, null, null, null)
33
+ val cursor = cursorLoader.loadInBackground()
34
+ if (cursor != null) {
35
+ val column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
36
+ cursor.moveToFirst()
37
+ result = cursor.getString(column_index)
38
+ cursor.close()
39
+ }
40
+ return result
41
+ }
42
+
43
+ fun getRealPathFromURI_BelowAPI11(context: Context, contentUri: Uri?): String {
44
+ val proj = arrayOf(MediaStore.Images.Media.DATA)
45
+ val cursor = context.contentResolver.query(contentUri!!, proj, null, null, null)
46
+ var column_index = 0
47
+ var result = ""
48
+ if (cursor != null) {
49
+ column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
50
+ cursor.moveToFirst()
51
+ result = cursor.getString(column_index)
52
+ cursor.close()
53
+ return result
54
+ }
55
+ return result
56
+ }
57
+
58
+ /**
59
+ * Get a file path from a Uri. This will get the the path for Storage Access
60
+ * Framework Documents, as well as the _data field for the MediaStore and
61
+ * other file-based ContentProviders.
62
+ *
63
+ * @param context The context.
64
+ * @param uri The Uri to query.
65
+ * @author paulburke
66
+ */
67
+ @SuppressLint("NewApi")
68
+ fun getRealPathFromURI_API19(context: Context, uri: Uri): String? {
69
+ val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
70
+
71
+ // DocumentProvider
72
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
73
+ // ExternalStorageProvider
74
+ if (isExternalStorageDocument(uri)) {
75
+ val docId = DocumentsContract.getDocumentId(uri)
76
+ val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
77
+ val type = split[0]
78
+ if ("primary".equals(type, ignoreCase = true)) {
79
+ return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
80
+ }
81
+
82
+ // TODO handle non-primary volumes
83
+ } else if (isDownloadsDocument(uri)) {
84
+ val id = DocumentsContract.getDocumentId(uri)
85
+ val contentUri = ContentUris.withAppendedId(
86
+ Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
87
+ return getDataColumn(context, contentUri, null, null)
88
+ } else if (isMediaDocument(uri)) {
89
+ val docId = DocumentsContract.getDocumentId(uri)
90
+ val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
91
+ val type = split[0]
92
+ var contentUri: Uri? = null
93
+ if ("image" == type) {
94
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
95
+ } else if ("video" == type) {
96
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
97
+ } else if ("audio" == type) {
98
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
99
+ }
100
+ val selection = "_id=?"
101
+ val selectionArgs = arrayOf(
102
+ split[1]
103
+ )
104
+ return getDataColumn(context, contentUri, selection, selectionArgs)
105
+ }
106
+ } else if ("content".equals(uri.scheme, ignoreCase = true)) {
107
+
108
+ // Return the remote address
109
+ return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)
110
+ } else if ("file".equals(uri.scheme, ignoreCase = true)) {
111
+ return uri.path
112
+ }
113
+ return null
114
+ }
115
+
116
+ /**
117
+ * Get the value of the data column for this Uri. This is useful for
118
+ * MediaStore Uris, and other file-based ContentProviders.
119
+ *
120
+ * @param context The context.
121
+ * @param uri The Uri to query.
122
+ * @param selection (Optional) Filter used in the query.
123
+ * @param selectionArgs (Optional) Selection arguments used in the query.
124
+ * @return The value of the _data column, which is typically a file path.
125
+ */
126
+ fun getDataColumn(context: Context, uri: Uri?, selection: String?,
127
+ selectionArgs: Array<String>?): String? {
128
+ var cursor: Cursor? = null
129
+ val column = "_data"
130
+ val projection = arrayOf(
131
+ column
132
+ )
133
+ try {
134
+ cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs,
135
+ null)
136
+ if (cursor != null && cursor.moveToFirst()) {
137
+ val index = cursor.getColumnIndexOrThrow(column)
138
+ return cursor.getString(index)
139
+ }
140
+ } finally {
141
+ cursor?.close()
142
+ }
143
+ return null
144
+ }
145
+
146
+ /**
147
+ * @param uri The Uri to check.
148
+ * @return Whether the Uri authority is ExternalStorageProvider.
149
+ */
150
+ fun isExternalStorageDocument(uri: Uri): Boolean {
151
+ return "com.android.externalstorage.documents" == uri.authority
152
+ }
153
+
154
+ /**
155
+ * @param uri The Uri to check.
156
+ * @return Whether the Uri authority is DownloadsProvider.
157
+ */
158
+ fun isDownloadsDocument(uri: Uri): Boolean {
159
+ return "com.android.providers.downloads.documents" == uri.authority
160
+ }
161
+
162
+ /**
163
+ * @param uri The Uri to check.
164
+ * @return Whether the Uri authority is MediaProvider.
165
+ */
166
+ fun isMediaDocument(uri: Uri): Boolean {
167
+ return "com.android.providers.media.documents" == uri.authority
168
+ }
169
+
170
+ /**
171
+ * @param uri The Uri to check.
172
+ * @return Whether the Uri authority is Google Photos.
173
+ */
174
+ fun isGooglePhotosUri(uri: Uri): Boolean {
175
+ return "com.google.android.apps.photos.content" == uri.authority
176
+ }
177
+ }
@@ -0,0 +1,117 @@
1
+ package com.reactnativecompressor.Utils
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReadableMap
8
+ import io.github.lizhangqu.coreprogress.ProgressHelper
9
+ import io.github.lizhangqu.coreprogress.ProgressUIListener
10
+ import okhttp3.Call
11
+ import okhttp3.Callback
12
+ import okhttp3.MediaType
13
+ import okhttp3.MediaType.Companion.toMediaTypeOrNull
14
+ import okhttp3.OkHttpClient
15
+ import okhttp3.Request.Builder
16
+ import okhttp3.RequestBody
17
+ import okhttp3.Response
18
+ import java.io.File
19
+ import java.io.IOException
20
+ import java.util.Locale
21
+
22
+ object Uploader {
23
+ private const val TAG = "asyncTaskUploader"
24
+
25
+ fun upload(fileUrl: String, _options: ReadableMap?, reactContext: ReactApplicationContext, promise: Promise) {
26
+ val options = _options?.let { UploaderHelper.fromMap(it) }
27
+ val uploadableFile = File(fileUrl)
28
+ val url = options?.url
29
+ var contentType: String? = "video"
30
+ val okHttpClient = OkHttpClient()
31
+ val builder = Builder()
32
+ if (url != null) {
33
+ builder.url(url)
34
+ }
35
+ val headerIterator = options!!.headers!!.keySetIterator()
36
+ while (headerIterator.hasNextKey()) {
37
+ val key = headerIterator.nextKey()
38
+ val value = options.headers!!.getString(key)
39
+ Log.d(TAG, "$key value: $value")
40
+ builder.addHeader(key, value.toString())
41
+ if (key.lowercase(Locale.getDefault()) === "content-type:") {
42
+ contentType = value
43
+ }
44
+ }
45
+ val mediaType: MediaType = contentType?.toMediaTypeOrNull()!!;
46
+ val body = RequestBody.create(mediaType, uploadableFile)
47
+ val requestBody = ProgressHelper.withProgress(body, object : ProgressUIListener() {
48
+ //if you don't need this method, don't override this methd. It isn't an abstract method, just an empty method.
49
+ override fun onUIProgressStart(totalBytes: Long) {
50
+ super.onUIProgressStart(totalBytes)
51
+ Log.d(TAG, "onUIProgressStart:$totalBytes")
52
+ }
53
+
54
+ override fun onUIProgressChanged(numBytes: Long, totalBytes: Long, percent: Float, speed: Float) {
55
+ EventEmitterHandler.sendUploadProgressEvent(numBytes,totalBytes,options.uuid)
56
+ Log.d(TAG, "=============start===============")
57
+ Log.d(TAG, "numBytes:$numBytes")
58
+ Log.d(TAG, "totalBytes:$totalBytes")
59
+ Log.d(TAG, "percent:$percent")
60
+ Log.d(TAG, "speed:$speed")
61
+ Log.d(TAG, "============= end ===============")
62
+ }
63
+
64
+ //if you don't need this method, don't override this methd. It isn't an abstract method, just an empty method.
65
+ override fun onUIProgressFinish() {
66
+ super.onUIProgressFinish()
67
+ Log.d(TAG, "onUIProgressFinish:")
68
+ }
69
+ })
70
+ builder.put(requestBody)
71
+ val call = okHttpClient.newCall(builder.build())
72
+ call.enqueue(object : Callback {
73
+ override fun onFailure(call: Call, e: IOException) {
74
+ Log.d(TAG, "=============onFailure===============")
75
+ promise.reject("")
76
+ e.printStackTrace()
77
+ }
78
+
79
+ @Throws(IOException::class)
80
+ override fun onResponse(call: Call, response: Response) {
81
+ Log.d(TAG, "=============onResponse===============")
82
+ Log.d(TAG, "request headers:" + response.request.headers)
83
+ Log.d(TAG, "response code:" + response.code)
84
+ Log.d(TAG, "response headers:" + response.headers)
85
+ Log.d(TAG, "response body:" + response.body!!.string())
86
+ val param = Arguments.createMap()
87
+ param.putInt("status", response.code)
88
+ promise.resolve(param)
89
+ }
90
+ })
91
+ }
92
+ }
93
+
94
+
95
+ class UploaderHelper {
96
+ var uuid: String? = null
97
+ var method: String? = null
98
+ var headers: ReadableMap? = null
99
+ var url: String? = null
100
+
101
+ companion object {
102
+ fun fromMap(map: ReadableMap): UploaderHelper {
103
+ val options = UploaderHelper()
104
+ val iterator = map.keySetIterator()
105
+ while (iterator.hasNextKey()) {
106
+ val key = iterator.nextKey()
107
+ when (key) {
108
+ "uuid" -> options.uuid = map.getString(key)
109
+ "method" -> options.method = map.getString(key)
110
+ "headers" -> options.headers = map.getMap(key)
111
+ "url" -> options.url = map.getString(key)
112
+ }
113
+ }
114
+ return options
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,162 @@
1
+ package com.reactnativecompressor.Utils
2
+
3
+ import android.content.ContentResolver
4
+ import android.content.res.AssetFileDescriptor
5
+ import android.net.Uri
6
+ import android.provider.OpenableColumns
7
+ import android.util.Log
8
+ import com.facebook.react.bridge.Promise
9
+ import com.facebook.react.bridge.ReactApplicationContext
10
+ import numan.dev.videocompressor.VideoCompressTask
11
+ import numan.dev.videocompressor.VideoCompressor
12
+ import java.io.FileNotFoundException
13
+ import java.io.IOException
14
+ import java.net.HttpURLConnection
15
+ import java.net.URL
16
+ import java.util.UUID
17
+
18
+ object Utils {
19
+ private const val TAG = "react-native-compessor"
20
+ var compressorExports: MutableMap<String, VideoCompressTask> = HashMap()
21
+ @JvmStatic
22
+ fun generateCacheFilePath(extension: String, reactContext: ReactApplicationContext): String {
23
+ val outputDir = reactContext.cacheDir
24
+ return String.format("%s/%s.$extension", outputDir.path, UUID.randomUUID().toString())
25
+ }
26
+
27
+ @JvmStatic
28
+ fun compressVideo(srcPath: String, destinationPath: String, resultWidth: Int, resultHeight: Int, videoBitRate: Float, uuid: String,progressDivider:Int, promise: Promise, reactContext: ReactApplicationContext) {
29
+ val currentVideoCompression = intArrayOf(0)
30
+ try {
31
+ val export = VideoCompressor.convertVideo(srcPath, destinationPath, resultWidth, resultHeight, videoBitRate.toInt(), object : VideoCompressor.ProgressListener {
32
+ override fun onStart() {
33
+ //convert start
34
+ }
35
+
36
+ override fun onFinish(result: Boolean) {
37
+ val fileUrl = "file://$destinationPath"
38
+ //convert finish,result(true is success,false is fail)
39
+ promise.resolve(fileUrl)
40
+ MediaCache.removeCompletedImagePath(fileUrl)
41
+ }
42
+
43
+ override fun onError(errorMessage: String) {
44
+ if (errorMessage == "class java.lang.AssertionError") {
45
+ promise.resolve("file://$srcPath")
46
+ } else {
47
+ promise.reject("Compression has canncelled")
48
+ }
49
+ }
50
+
51
+ override fun onProgress(percent: Float) {
52
+ val roundProgress = Math.round(percent)
53
+ if (progressDivider==0||(roundProgress % progressDivider == 0 && roundProgress > currentVideoCompression[0])) {
54
+ EventEmitterHandler.emitVideoCompressProgress((percent / 100).toDouble(),uuid)
55
+ currentVideoCompression[0] = roundProgress
56
+ }
57
+ }
58
+ })
59
+ compressorExports[uuid] = export
60
+ } catch (ex: Exception) {
61
+ promise.reject(ex)
62
+ } finally {
63
+ currentVideoCompression[0] = 0
64
+ }
65
+ }
66
+
67
+ fun cancelCompressionHelper(uuid: String) {
68
+ try {
69
+ val export = compressorExports[uuid]
70
+ export!!.cancel(true)
71
+ } catch (ex: Exception) {
72
+ }
73
+ }
74
+
75
+ @JvmStatic
76
+ fun getFileSizeFromURL(urlString: String?): Int {
77
+ val url: URL
78
+ var conn: HttpURLConnection? = null
79
+ return try {
80
+ url = URL(urlString)
81
+ conn = url.openConnection() as HttpURLConnection
82
+ conn.requestMethod = "HEAD"
83
+ conn!!.inputStream
84
+ conn.contentLength
85
+ } catch (e: IOException) {
86
+ throw RuntimeException(e)
87
+ } finally {
88
+ conn?.disconnect()
89
+ }
90
+ }
91
+
92
+ @JvmStatic
93
+ fun getRealPath(fileUrl: String?, reactContext: ReactApplicationContext, vararg args: Any?): String? {
94
+ var fileUrl = fileUrl
95
+ if (fileUrl!!.startsWith("content://")) {
96
+ try {
97
+ val uri = Uri.parse(fileUrl)
98
+ fileUrl = RealPathUtil.getRealPath(reactContext, uri)
99
+ } catch (ex: Exception) {
100
+ Log.d(TAG, " Please see this issue: https://github.com/numandev1/react-native-compressor/issues/25")
101
+ }
102
+ } else if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) {
103
+ val uuid: String = if (args.size > 0) args[0].toString() else ""
104
+ val progressDivider: Int = if (args.size > 1) args[1] as Int else 0
105
+ fileUrl = Downloader.downloadMediaWithProgress(fileUrl, uuid,progressDivider, reactContext)
106
+ Log.d(TAG, "getRealPath: $fileUrl")
107
+ }
108
+ return fileUrl
109
+ }
110
+
111
+
112
+
113
+ fun getFileSize(filePath: String, promise: Promise, reactContext:ReactApplicationContext) {
114
+ var filePath: String? = filePath
115
+ if (filePath!!.startsWith("http://") || filePath.startsWith("https://")) {
116
+ promise.resolve(getFileSizeFromURL(filePath))
117
+ } else {
118
+ filePath = getRealPath(filePath, reactContext)
119
+ val uri = Uri.parse(filePath)
120
+ val contentResolver = reactContext.contentResolver
121
+ val fileSize = getLength(uri, contentResolver)
122
+ if (fileSize >= 0) {
123
+ promise.resolve(fileSize.toString())
124
+ } else {
125
+ promise.resolve("")
126
+ }
127
+ }
128
+ }
129
+
130
+ fun getLength(uri: Uri, contentResolver: ContentResolver): Long {
131
+ var assetFileDescriptor: AssetFileDescriptor? = null
132
+ try {
133
+ assetFileDescriptor = contentResolver.openAssetFileDescriptor(uri, "r")
134
+ } catch (e: FileNotFoundException) {
135
+ // Do nothing
136
+ }
137
+ val length = assetFileDescriptor?.length ?: -1L
138
+ if (length != -1L) {
139
+ return length
140
+ }
141
+ return if (ContentResolver.SCHEME_CONTENT == uri.scheme) {
142
+ val cursor = contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)
143
+ if (cursor != null) {
144
+ try {
145
+ val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
146
+ if (sizeIndex != -1 && cursor.moveToFirst()) {
147
+ return try {
148
+ cursor.getLong(sizeIndex)
149
+ } catch (ignored: Throwable) {
150
+ -1L
151
+ }
152
+ }
153
+ } finally {
154
+ cursor.close()
155
+ }
156
+ }
157
+ -1L
158
+ } else {
159
+ -1L
160
+ }
161
+ }
162
+ }
@@ -0,0 +1,63 @@
1
+ package com.reactnativecompressor.Video
2
+
3
+ import android.media.MediaMetadataRetriever
4
+ import android.net.Uri
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.reactnativecompressor.Utils.Utils.compressVideo
8
+ import com.reactnativecompressor.Utils.Utils.generateCacheFilePath
9
+ import java.io.File
10
+
11
+ object AutoVideoCompression {
12
+ fun createCompressionSettings(fileUrl: String?, options: VideoCompressorHelper, promise: Promise, reactContext: ReactApplicationContext?) {
13
+ val maxSize = options.maxSize
14
+ val minimumFileSizeForCompress = options.minimumFileSizeForCompress
15
+ try {
16
+ val uri = Uri.parse(fileUrl)
17
+ val srcPath = uri.path
18
+ val metaRetriever = MediaMetadataRetriever()
19
+ metaRetriever.setDataSource(srcPath)
20
+ val file = File(srcPath)
21
+ val sizeInBytes = file.length().toFloat()
22
+ val sizeInMb = sizeInBytes / (1024 * 1024)
23
+ if (sizeInMb > minimumFileSizeForCompress) {
24
+ val destinationPath = generateCacheFilePath("mp4", reactContext!!)
25
+ val actualHeight = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)!!.toInt()
26
+ val actualWidth = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)!!.toInt()
27
+ val bitrate = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)!!.toInt()
28
+ val scale = if (actualWidth > actualHeight) maxSize / actualWidth else maxSize / actualHeight
29
+ val resultWidth = Math.round(actualWidth * scale / 2) * 2
30
+ val resultHeight = Math.round(actualHeight * scale / 2) * 2
31
+ val videoBitRate = makeVideoBitrate(
32
+ actualHeight, actualWidth,
33
+ bitrate,
34
+ resultHeight, resultWidth
35
+ ).toFloat()
36
+ compressVideo(srcPath!!, destinationPath, resultWidth, resultHeight, videoBitRate, options.uuid!!,options.progressDivider!!, promise, reactContext)
37
+ } else {
38
+ promise.resolve(fileUrl)
39
+ }
40
+ } catch (ex: Exception) {
41
+ promise.reject(ex)
42
+ }
43
+ }
44
+
45
+ fun makeVideoBitrate(originalHeight: Int, originalWidth: Int, originalBitrate: Int, height: Int, width: Int): Int {
46
+ val compressFactor = 0.8f
47
+ val minCompressFactor = 0.8f
48
+ val maxBitrate = 1669000
49
+ var remeasuredBitrate = (originalBitrate / Math.min(originalHeight / height.toFloat(), originalWidth / width.toFloat())).toInt()
50
+ remeasuredBitrate = (remeasuredBitrate * compressFactor).toInt()
51
+ val minBitrate = (getVideoBitrateWithFactor(minCompressFactor) / (1280f * 720f / (width * height))).toInt()
52
+ if (originalBitrate < minBitrate) {
53
+ return remeasuredBitrate
54
+ }
55
+ return if (remeasuredBitrate > maxBitrate) {
56
+ maxBitrate
57
+ } else Math.max(remeasuredBitrate, minBitrate)
58
+ }
59
+
60
+ private fun getVideoBitrateWithFactor(f: Float): Int {
61
+ return (f * 2000f * 1000f * 1.13f).toInt()
62
+ }
63
+ }