react-native-compressor 1.8.16 → 1.8.18

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 (58) hide show
  1. package/README.md +103 -10
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +58 -27
  4. package/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt +49 -0
  5. package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +2 -6
  6. package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +5 -0
  7. package/android/src/main/java/com/reactnativecompressor/Utils/HttpCallManager.kt +41 -0
  8. package/android/src/main/java/com/reactnativecompressor/Utils/Uploader.kt +70 -33
  9. package/android/src/main/java/com/reactnativecompressor/Utils/createVideoThumbnail.kt +0 -2
  10. package/android/src/oldarch/CompressorSpec.kt +1 -0
  11. package/ios/Audio/AudioHelper.swift +49 -0
  12. package/ios/Audio/AudioMain.swift +46 -82
  13. package/ios/Audio/AudioOptions.swift +37 -0
  14. package/ios/Audio/FormatConverter/FormatConverter+Compressed.swift +326 -0
  15. package/ios/Audio/FormatConverter/FormatConverter+PCM.swift +239 -0
  16. package/ios/Audio/FormatConverter/FormatConverter+Utilities.swift +103 -0
  17. package/ios/Audio/FormatConverter/FormatConverter.swift +264 -0
  18. package/ios/Compressor.mm +4 -1
  19. package/ios/Compressor.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  20. package/ios/CompressorManager.swift +5 -0
  21. package/ios/Utils/Uploader.swift +18 -1
  22. package/ios/Utils/UrlTaskManager.swift +58 -0
  23. package/ios/Video/NextLevelSessionExporter.swift +694 -0
  24. package/ios/Video/VideoMain.swift +1 -2
  25. package/lib/commonjs/Audio/index.js +1 -3
  26. package/lib/commonjs/Audio/index.js.map +1 -1
  27. package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
  28. package/lib/commonjs/index.js +6 -0
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/commonjs/utils/Uploader.js +13 -2
  31. package/lib/commonjs/utils/Uploader.js.map +1 -1
  32. package/lib/commonjs/utils/index.js +0 -2
  33. package/lib/commonjs/utils/index.js.map +1 -1
  34. package/lib/module/Audio/index.js +1 -3
  35. package/lib/module/Audio/index.js.map +1 -1
  36. package/lib/module/Spec/NativeCompressor.js.map +1 -1
  37. package/lib/module/index.js +2 -2
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/utils/Uploader.js +11 -1
  40. package/lib/module/utils/Uploader.js.map +1 -1
  41. package/lib/module/utils/index.js +0 -3
  42. package/lib/module/utils/index.js.map +1 -1
  43. package/lib/typescript/Audio/index.d.ts.map +1 -1
  44. package/lib/typescript/Spec/NativeCompressor.d.ts +1 -0
  45. package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
  46. package/lib/typescript/index.d.ts +3 -3
  47. package/lib/typescript/index.d.ts.map +1 -1
  48. package/lib/typescript/utils/Uploader.d.ts +3 -1
  49. package/lib/typescript/utils/Uploader.d.ts.map +1 -1
  50. package/lib/typescript/utils/index.d.ts +4 -1
  51. package/lib/typescript/utils/index.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/react-native-compressor.podspec +0 -1
  54. package/src/Audio/index.tsx +1 -3
  55. package/src/Spec/NativeCompressor.ts +2 -0
  56. package/src/index.tsx +2 -0
  57. package/src/utils/Uploader.tsx +18 -1
  58. package/src/utils/index.tsx +5 -2
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  <div align="center">
2
- <img height="150" src="/media/logo.png"></h2>
2
+ <img height="150" src="/media/logo.png" />
3
3
  </div>
4
+
4
5
  <br/>
5
6
 
6
7
  <div align="center">
@@ -15,6 +16,11 @@
15
16
 
16
17
  **REACT-NATIVE-COMPRESSOR** is a react-native package, which helps us to Compress `Image`, `Video`, and `Audio` before uploading, same like **Whatsapp** without knowing the compression `algorithm`
17
18
 
19
+ <div align="center">
20
+ <b>Also supports Auto/Manual Compression | Background Upload | Download File | Create Video Thumbnail</b>
21
+ </div>
22
+ <br/>
23
+
18
24
  <div align="center">
19
25
  <pre>
20
26
  <img height="90" src="/media/whatsapp_logo.png"/> <img height="90" src="/media/compress_media.png"/>
@@ -129,9 +135,9 @@ react-native link react-native-compressor
129
135
 
130
136
  #### iOS
131
137
 
132
- 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
133
- 2. Go to `node_modules` `react-native-compressor` and add `Compressor.xcodeproj`
134
- 3. In XCode, in the project navigator, select your project. Add `libCompressor.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
138
+ 1. In XCode, open Podfile
139
+ 2. paste this line `pod 'react-native-compressor', :path => '../node_modules/react-native-compressor'` into `Podfile`
140
+ 3. run this command inside ios folder `pod install`
135
141
  4. Run your project (`Cmd+R`)<
136
142
 
137
143
  #### Android
@@ -270,6 +276,17 @@ const result = await Audio.compress(
270
276
  'file://path_of_file/file_example_MP3_2MG.wav', // recommended wav file but can be use mp3 file
271
277
  { quality: 'medium' }
272
278
  );
279
+
280
+ // OR
281
+
282
+ const result = await Audio.compress(
283
+ 'file://path_of_file/file_example_MP3_2MG.wav', // recommended wav file but can be use mp3 file
284
+ {
285
+ bitrate: 64000,
286
+ samplerate: 44100,
287
+ channels: 1,
288
+ }
289
+ );
273
290
  ```
274
291
 
275
292
  ### Background Upload
@@ -300,6 +317,53 @@ const uploadResult = await backgroundUpload(
300
317
  );
301
318
  ```
302
319
 
320
+ ### Cancel Background Upload
321
+ for cancellation Upload, there is two ways
322
+ 1. by calling, cancelUpload function
323
+ 2. by calling abort function
324
+
325
+ ##### cancelUpload (support single and all)
326
+ ```js
327
+ import { cancelUpload, backgroundUpload } from 'react-native-compressor';
328
+
329
+ // if we will call without passing any param then it will remove last pushed uploading
330
+ cancelUpload()
331
+
332
+ // if you pass true as second param then it will cancel all the uploading
333
+ cancelUpload("",true)
334
+
335
+ // if there is multiple files are uploading, and you wanna cancel specific uploading then you pass specific video id like this
336
+ let videoId=''
337
+ const uploadResult = await backgroundUpload(
338
+ url,
339
+ fileUrl,
340
+ { httpMethod: 'PUT', getCancellationId: (cancellationId) =>(videoId = cancellationId), },
341
+ (written, total) => {
342
+ console.log(written, total);
343
+ }
344
+ );
345
+ cancelUpload(videoId)
346
+ ```
347
+
348
+ ##### cancel by calling abort
349
+ ```js
350
+ import { backgroundUpload } from 'react-native-compressor';
351
+
352
+ const abortSignalRef = useRef(new AbortController());
353
+
354
+ const uploadResult = await backgroundUpload(
355
+ url,
356
+ fileUrl,
357
+ { httpMethod: 'PUT' },
358
+ (written, total) => {
359
+ console.log(written, total);
360
+ },
361
+ abortSignalRef.current.signal
362
+ );
363
+
364
+ abortSignalRef.current?.abort(); // this will cancel uploading
365
+ ```
366
+
303
367
  ### Download File
304
368
 
305
369
  ```js
@@ -377,8 +441,14 @@ await clearCache(); // this will clear cache of thumbnails cache directory
377
441
  - ###### `compress(url: string, options?: videoCompresssionType , onProgress?: (progress: number)): Promise<string>`
378
442
 
379
443
  - ###### `cancelCompression(cancellationId: string): void`
444
+
380
445
  we can get cancellationId from `getCancellationId` which is the callback method of compress method options
381
446
 
447
+ - ###### `activateBackgroundTask(onExpired?: (data: any) => void): Promise<any>`
448
+ if you wanna compress video while app is in backgroup then you should call this method before compression
449
+ - ###### `deactivateBackgroundTask(): Promise<any>`
450
+ if you call `activateBackgroundTask` method, then after video compression, you should call `deactivateBackgroundTask` for disable background task mode.
451
+
382
452
  ### videoCompresssionType
383
453
 
384
454
  - ###### `compressionMethod: compressionMethod` (default: "manual")
@@ -415,10 +485,20 @@ await clearCache(); // this will clear cache of thumbnails cache directory
415
485
 
416
486
  ### audioCompresssionType
417
487
 
418
- - ###### `quality: qualityType` (default: medium)
488
+ - ###### `quality?: qualityType` (default: medium)
489
+
419
490
  we can also control bitrate through quality. qualityType can be `low` | `medium` | `high`
420
491
 
421
- **Note: manual bitrate, samplerate etc will add soon**
492
+ - ###### `bitrate?: number` Range [64000-320000]
493
+
494
+ we can control bitrate of audio through bitrate, it should be in the range of `64000-320000`
495
+
496
+ - ###### `samplerate?: number` Range [44100 - 192000]
497
+
498
+ we can control samplerate of audio through samplerate, it should be in the range of `44100 - 192000`
499
+
500
+ - ###### `channels?: number` Typically 1 or 2
501
+ we can control channels of audio through channels, Typically 1 or 2
422
502
 
423
503
  ## Background Upload
424
504
 
@@ -460,12 +540,25 @@ export declare type UploaderOptions = (
460
540
  ) & {
461
541
  headers?: Record<string, string>;
462
542
  httpMethod?: UploaderHttpMethod;
543
+ getCancellationId?: (cancellationId: string) => void;
463
544
  };
464
545
  ```
465
546
 
466
547
  **Note:** some of the uploader code is borrowed from [Expo](https://github.com/expo/expo)
467
548
  I tested file uploader on this backend [Nodejs-File-Uploader](https://github.com/numandev1/nodejs-file-uploader)
468
549
 
550
+ ### Cancel Background Upload
551
+ for cancellation Upload, there is two ways, you can use one of it
552
+ - ##### cancelUpload: ( uuid?: string, shouldCancelAll?: boolean) => void
553
+ 1. If we call without passing any param then it will remove the last pushed uploading
554
+ 2. If you pass true as the second param then it will cancel all the uploading
555
+ 3. if there is multiple files are uploading, and you wanna cancel specific uploading then you pass a specific video ID like this
556
+
557
+ - ##### we can use [AbortController](https://github.com/facebook/react-native/blob/255fef5263afdf9933ba2f8a3dbcbca39ea9928a/packages/react-native/types/modules/globals.d.ts#L531) in backgroundUpload [Usage](#cancel-background-upload)
558
+ `const abortSignalRef = useRef(new AbortController());`
559
+
560
+ `abortSignalRef.current?.abort();`
561
+
469
562
  ### Download
470
563
 
471
564
  - ##### download: ( fileUrl: string, downloadProgress?: (progress: number) => void, progressDivider?: number ) => Promise< string >
@@ -492,11 +585,11 @@ const metaData = await getVideoMetaData(filePath);
492
585
 
493
586
  ```
494
587
  {
495
- "duration": "6",
588
+ "duration": 20.11,
496
589
  "extension": "mp4",
497
- "height": "1080",
498
- "size": "16940.0",
499
- "width": "1920"
590
+ "height": 1080,
591
+ "size": 16940.0,
592
+ "width": 1920
500
593
  }
501
594
  ```
502
595
 
@@ -78,8 +78,8 @@ android {
78
78
  }
79
79
 
80
80
  compileOptions {
81
- sourceCompatibility JavaVersion.VERSION_1_8
82
- targetCompatibility JavaVersion.VERSION_1_8
81
+ sourceCompatibility JavaVersion.VERSION_11
82
+ targetCompatibility JavaVersion.VERSION_11
83
83
  }
84
84
 
85
85
  sourceSets {
@@ -4,6 +4,7 @@ package com.reactnativecompressor.Audio
4
4
  import android.annotation.SuppressLint
5
5
  import com.facebook.react.bridge.Promise
6
6
  import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReadableMap
7
8
  import com.naman14.androidlame.LameBuilder
8
9
  import com.naman14.androidlame.WaveReader
9
10
  import com.reactnativecompressor.Utils.MediaCache
@@ -27,21 +28,22 @@ class AudioCompressor {
27
28
  @JvmStatic
28
29
  fun CompressAudio(
29
30
  fileUrl: String,
30
- quality: String,
31
+ optionMap: ReadableMap,
31
32
  context: ReactApplicationContext,
32
33
  promise: Promise,
33
34
  ) {
34
- var _fileUrl=fileUrl
35
+ val realPath = Utils.getRealPath(fileUrl, context)
36
+ var _fileUrl=realPath
37
+ val filePathWithoutFileUri = realPath!!.replace("file://", "")
35
38
  try {
36
- val filePath = fileUrl.replace("file://", "")
37
- var wavPath=filePath;
39
+ var wavPath=filePathWithoutFileUri;
38
40
  var isNonWav:Boolean=false
39
41
  if (fileUrl.endsWith(".mp4", ignoreCase = true))
40
42
  {
41
43
  addLog("mp4 file found")
42
44
  val mp3Path= Utils.generateCacheFilePath("mp3", context)
43
45
  AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false)
44
- _fileUrl="file:/"+mp3Path
46
+ _fileUrl=Utils.slashifyFilePath(mp3Path)
45
47
  wavPath= Utils.generateCacheFilePath("wav", context)
46
48
  try {
47
49
  val converter = Converter()
@@ -58,7 +60,7 @@ class AudioCompressor {
58
60
  wavPath= Utils.generateCacheFilePath("wav", context)
59
61
  try {
60
62
  val converter = Converter()
61
- converter.convert(filePath, wavPath)
63
+ converter.convert(filePathWithoutFileUri, wavPath)
62
64
  } catch (e: JavaLayerException) {
63
65
  addLog("JavaLayerException error"+e.localizedMessage)
64
66
  e.printStackTrace();
@@ -67,7 +69,7 @@ class AudioCompressor {
67
69
  }
68
70
 
69
71
 
70
- autoCompressHelper(wavPath, quality,context) { mp3Path, finished ->
72
+ autoCompressHelper(wavPath,filePathWithoutFileUri, optionMap,context) { mp3Path, finished ->
71
73
  if (finished) {
72
74
  val returnableFilePath:String="file://$mp3Path"
73
75
  addLog("finished: " + returnableFilePath)
@@ -87,28 +89,23 @@ class AudioCompressor {
87
89
  }
88
90
  }
89
91
 
90
- private fun getAudioBitrateByQuality(quality: String): Int {
91
- return when (quality) {
92
- "low" -> 64 // Set your low bitrate value here
93
- "medium" -> 128 // Set your medium bitrate value here
94
- "high" -> 256 // Set your high bitrate value here
95
- else -> 128 // Default to medium bitrate if quality is not recognized
96
- }
97
- }
98
-
99
92
  @SuppressLint("WrongConstant")
100
93
  private fun autoCompressHelper(
101
94
  fileUrl: String,
102
- quality: String,
95
+ actualFileUrl: String,
96
+ optionMap: ReadableMap,
103
97
  context: ReactApplicationContext,
104
98
  completeCallback: (String, Boolean) -> Unit
105
99
  ) {
100
+
101
+ val options = AudioHelper.fromMap(optionMap)
102
+ val quality = options.quality
103
+
106
104
  var isCompletedCallbackTriggered:Boolean=false
107
105
  try {
108
106
  var mp3Path = Utils.generateCacheFilePath("mp3", context)
109
107
  val input = File(fileUrl)
110
108
  val output = File(mp3Path)
111
- val audioBitrate= getAudioBitrateByQuality(quality)
112
109
 
113
110
  val CHUNK_SIZE = 8192
114
111
  addLog("Initialising wav reader")
@@ -122,12 +119,46 @@ class AudioCompressor {
122
119
  }
123
120
 
124
121
  addLog("Intitialising encoder")
125
- val androidLame = LameBuilder()
126
- .setInSampleRate(waveReader!!.sampleRate)
127
- .setOutChannels(waveReader!!.channels)
128
- .setOutBitrate(audioBitrate)
129
- .setOutSampleRate(waveReader!!.sampleRate)
130
- .build()
122
+
123
+
124
+ // for bitrate
125
+ var audioBitrate:Int
126
+ if(options.bitrate != -1)
127
+ {
128
+ audioBitrate= options.bitrate/1000
129
+ }
130
+ else
131
+ {
132
+ audioBitrate=AudioHelper.getDestinationBitrateByQuality(actualFileUrl, quality!!)
133
+ Utils.addLog("dest bitrate: $audioBitrate")
134
+ }
135
+
136
+ var androidLame = LameBuilder();
137
+ androidLame.setOutBitrate(audioBitrate)
138
+
139
+ // for channels
140
+ var audioChannels:Int
141
+ if(options.channels != -1){
142
+ audioChannels= options.channels!!
143
+ }
144
+ else
145
+ {
146
+ audioChannels=waveReader!!.channels
147
+ }
148
+ androidLame.setOutChannels(audioChannels)
149
+
150
+ // for sample rate
151
+ androidLame.setInSampleRate(waveReader!!.sampleRate)
152
+ var audioSampleRate:Int
153
+ if(options.samplerate != -1){
154
+ audioSampleRate= options.samplerate!!
155
+ }
156
+ else
157
+ {
158
+ audioSampleRate=waveReader!!.sampleRate
159
+ }
160
+ androidLame.setOutSampleRate(audioSampleRate)
161
+ val androidLameBuild=androidLame.build()
131
162
 
132
163
  try {
133
164
  outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER)
@@ -154,7 +185,7 @@ class AudioCompressor {
154
185
  if (bytesRead > 0) {
155
186
 
156
187
  var bytesEncoded = 0
157
- bytesEncoded = androidLame.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
188
+ bytesEncoded = androidLameBuild.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
158
189
  addLog("bytes encoded=$bytesEncoded")
159
190
 
160
191
  if (bytesEncoded > 0) {
@@ -177,7 +208,7 @@ class AudioCompressor {
177
208
  if (bytesRead > 0) {
178
209
  var bytesEncoded = 0
179
210
 
180
- bytesEncoded = androidLame.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
211
+ bytesEncoded = androidLameBuild.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
181
212
  addLog("bytes encoded=$bytesEncoded")
182
213
 
183
214
  if (bytesEncoded > 0) {
@@ -202,7 +233,7 @@ class AudioCompressor {
202
233
  }
203
234
 
204
235
  addLog("flushing final mp3buffer")
205
- val outputMp3buf = androidLame.flush(mp3Buf)
236
+ val outputMp3buf = androidLameBuild.flush(mp3Buf)
206
237
  addLog("flushed $outputMp3buf bytes")
207
238
  if (outputMp3buf > 0) {
208
239
  try {
@@ -1,10 +1,19 @@
1
1
  package com.reactnativecompressor.Audio
2
2
 
3
+ import android.media.MediaExtractor
4
+ import android.media.MediaFormat
3
5
  import com.facebook.react.bridge.ReadableMap
6
+ import com.reactnativecompressor.Utils.Utils
7
+ import java.io.File
8
+ import java.io.IOException
9
+
4
10
 
5
11
  class AudioHelper {
6
12
 
7
13
  var quality: String? = "medium"
14
+ var bitrate: Int = -1
15
+ var samplerate: Int = -1
16
+ var channels: Int = -1
8
17
  var progressDivider: Int? = 0
9
18
 
10
19
  companion object {
@@ -15,9 +24,49 @@ class AudioHelper {
15
24
  val key = iterator.nextKey()
16
25
  when (key) {
17
26
  "quality" -> options.quality = map.getString(key)
27
+ "bitrate" -> {
28
+ val bitrate = map.getInt(key)
29
+ options.bitrate = if (bitrate > 320000 || bitrate < 64000) 64000 else bitrate
30
+ }
31
+ "samplerate" -> options.samplerate = map.getInt(key)
32
+ "channels" -> options.channels = map.getInt(key)
18
33
  }
19
34
  }
20
35
  return options
21
36
  }
37
+
38
+
39
+ fun getAudioBitrate(path: String): Int {
40
+ val file = File(path)
41
+ val fileSize = file.length() * 8 // size in bits
42
+
43
+ val mex = MediaExtractor()
44
+ try {
45
+ mex.setDataSource(path)
46
+ } catch (e: IOException) {
47
+ e.printStackTrace()
48
+ }
49
+
50
+ val mf = mex.getTrackFormat(0)
51
+ val durationUs = mf.getLong(MediaFormat.KEY_DURATION)
52
+ val durationSec = durationUs / 1_000_000.0 // convert duration to seconds
53
+
54
+ return (fileSize / durationSec).toInt()/1000 // bitrate in bits per second
55
+ }
56
+ fun getDestinationBitrateByQuality(path: String, quality: String): Int {
57
+ val originalBitrate = getAudioBitrate(path)
58
+ var destinationBitrate = originalBitrate
59
+ Utils.addLog("source bitrate: $originalBitrate")
60
+
61
+ when (quality.toLowerCase()) {
62
+ "low" -> destinationBitrate = maxOf(64, (originalBitrate * 0.3).toInt())
63
+ "medium" -> destinationBitrate = (originalBitrate * 0.5).toInt()
64
+ "high" -> destinationBitrate = minOf(320, (originalBitrate * 0.7).toInt())
65
+ else -> Utils.addLog("Invalid quality level. Please enter 'low', 'medium', or 'high'.")
66
+ }
67
+
68
+ return destinationBitrate
69
+ }
70
+
22
71
  }
23
72
  }
@@ -3,7 +3,6 @@ package com.reactnativecompressor.Audio
3
3
  import com.facebook.react.bridge.Promise
4
4
  import com.facebook.react.bridge.ReactApplicationContext
5
5
  import com.facebook.react.bridge.ReadableMap
6
- import com.reactnativecompressor.Utils.Utils
7
6
 
8
7
  class AudioMain(private val reactContext: ReactApplicationContext) {
9
8
  fun compress_audio(
@@ -11,11 +10,8 @@ class AudioMain(private val reactContext: ReactApplicationContext) {
11
10
  optionMap: ReadableMap,
12
11
  promise: Promise) {
13
12
  try {
14
- val options = AudioHelper.fromMap(optionMap)
15
- val quality = options.quality
16
- val realPath = Utils.getRealPath(fileUrl, reactContext)
17
- Utils.addLog(fileUrl + "\n realPath= " + realPath)
18
- AudioCompressor.CompressAudio(realPath!!, quality!!,reactContext,promise)
13
+
14
+ AudioCompressor.CompressAudio(fileUrl,optionMap,reactContext,promise)
19
15
  } catch (ex: Exception) {
20
16
  promise.reject(ex)
21
17
  }
@@ -125,6 +125,11 @@ class CompressorModule(private val reactContext: ReactApplicationContext) : Comp
125
125
  uploader.upload(fileUrl, options, reactContext, promise)
126
126
  }
127
127
 
128
+ @ReactMethod
129
+ override fun cancelUpload(uuid: String,shouldCancelAll:Boolean) {
130
+ uploader.cancelUpload(uuid,shouldCancelAll)
131
+ }
132
+
128
133
  @ReactMethod
129
134
  override fun download(
130
135
  fileUrl: String,
@@ -0,0 +1,41 @@
1
+ package com.reactnativecompressor.Utils
2
+
3
+ import okhttp3.Call
4
+
5
+ class HttpCallManager {
6
+ private var resumableCalls: MutableMap<String, Call?> = HashMap()
7
+
8
+ fun registerTask(call: Call, uuid: String) {
9
+ resumableCalls[uuid] = call
10
+ }
11
+
12
+ fun taskForId(uuid: String): Call? {
13
+ return resumableCalls[uuid]
14
+ }
15
+
16
+ // will use in future
17
+ fun downloadTaskForId(uuid: String): Call? {
18
+ return taskForId(uuid)
19
+ }
20
+
21
+ fun uploadTaskForId(uuid: String): Call? {
22
+ return taskForId(uuid)
23
+ }
24
+
25
+ fun taskPop(): Call? {
26
+ val lastUuid = resumableCalls.keys.lastOrNull()
27
+ val lastCall = resumableCalls.remove(lastUuid)
28
+ return lastCall
29
+ }
30
+
31
+ fun unregisterTask(uuid: String) {
32
+ resumableCalls.remove(uuid)
33
+ }
34
+
35
+ fun cancelAllTasks() {
36
+ for ((_, call) in resumableCalls) {
37
+ call?.cancel()
38
+ }
39
+ resumableCalls.clear()
40
+ }
41
+ }
@@ -26,36 +26,45 @@ import java.net.URLConnection
26
26
  import java.util.concurrent.TimeUnit
27
27
 
28
28
  class Uploader(private val reactContext: ReactApplicationContext) {
29
- val TAG = "asyncTaskUploader"
30
- var client: OkHttpClient? = null
31
- val MIN_EVENT_DT_MS: Long = 100
32
-
33
- fun upload(fileUriString: String, _options: ReadableMap, reactContext: ReactApplicationContext, promise: Promise) {
34
- val options:UploaderOptions=convertReadableMapToUploaderOptions(_options)
35
- val url = options.url
36
- val uuid = options.uuid
37
- val progressListener: CountingRequestListener = object : CountingRequestListener {
38
- private var mLastUpdate: Long = -1
39
- override fun onProgress(bytesWritten: Long, contentLength: Long) {
40
- val currentTime = System.currentTimeMillis()
41
-
42
- // Throttle events. Sending too many events will block the JS event loop.
43
- // Make sure to send the last event when we're at 100%.
44
- if (currentTime > mLastUpdate + MIN_EVENT_DT_MS || bytesWritten == contentLength) {
45
- mLastUpdate = currentTime
46
- EventEmitterHandler.sendUploadProgressEvent(bytesWritten,contentLength,uuid)
47
- }
29
+ val TAG = "asyncTaskUploader"
30
+ var client: OkHttpClient? = null
31
+ val MIN_EVENT_DT_MS: Long = 100
32
+ val httpCallManager = HttpCallManager()
33
+
34
+ fun upload(
35
+ fileUriString: String,
36
+ _options: ReadableMap,
37
+ reactContext: ReactApplicationContext,
38
+ promise: Promise
39
+ ) {
40
+ val options: UploaderOptions = convertReadableMapToUploaderOptions(_options)
41
+ val url = options.url
42
+ val uuid = options.uuid
43
+ val progressListener: CountingRequestListener = object : CountingRequestListener {
44
+ private var mLastUpdate: Long = -1
45
+ override fun onProgress(bytesWritten: Long, contentLength: Long) {
46
+ val currentTime = System.currentTimeMillis()
47
+
48
+ // Throttle events. Sending too many events will block the JS event loop.
49
+ // Make sure to send the last event when we're at 100%.
50
+ if (currentTime > mLastUpdate + MIN_EVENT_DT_MS || bytesWritten == contentLength) {
51
+ mLastUpdate = currentTime
52
+ EventEmitterHandler.sendUploadProgressEvent(bytesWritten, contentLength, uuid)
48
53
  }
49
54
  }
50
- val request = createUploadRequest(
51
- url, fileUriString, options
52
- ) { requestBody -> CountingRequestBody(requestBody, progressListener) }
53
-
54
- okHttpClient?.let {
55
- it.newCall(request).enqueue(object : Callback {
55
+ }
56
+ val request = createUploadRequest(
57
+ url, fileUriString, options
58
+ ) { requestBody -> CountingRequestBody(requestBody, progressListener) }
59
+
60
+ okHttpClient?.let {
61
+ val call = it.newCall(request)
62
+ httpCallManager.registerTask(call,uuid)
63
+ call.enqueue(
64
+ object : Callback {
56
65
  override fun onFailure(call: Call, e: IOException) {
57
66
  Log.e(TAG, e.message.toString())
58
- promise.reject(TAG, e.message, e)
67
+ promise.reject(TAG, e.message)
59
68
  }
60
69
 
61
70
  override fun onResponse(call: Call, response: Response) {
@@ -67,12 +76,12 @@ class Uploader(private val reactContext: ReactApplicationContext) {
67
76
  promise.resolve(param)
68
77
  }
69
78
  })
70
- } ?: run {
71
- promise.reject(UploaderOkHttpNullException())
72
- }
73
-
79
+ } ?: run {
80
+ promise.reject(UploaderOkHttpNullException())
74
81
  }
75
82
 
83
+ }
84
+
76
85
  @get:Synchronized
77
86
  private val okHttpClient: OkHttpClient?
78
87
  get() {
@@ -87,7 +96,12 @@ class Uploader(private val reactContext: ReactApplicationContext) {
87
96
  }
88
97
 
89
98
  @Throws(IOException::class)
90
- private fun createUploadRequest(url: String, fileUriString: String, options: UploaderOptions, decorator: RequestBodyDecorator): Request {
99
+ private fun createUploadRequest(
100
+ url: String,
101
+ fileUriString: String,
102
+ options: UploaderOptions,
103
+ decorator: RequestBodyDecorator
104
+ ): Request {
91
105
  val fileUri = Uri.parse(slashifyFilePath(fileUriString))
92
106
  fileUri.checkIfFileExists()
93
107
 
@@ -101,7 +115,11 @@ class Uploader(private val reactContext: ReactApplicationContext) {
101
115
  }
102
116
 
103
117
  @SuppressLint("NewApi")
104
- private fun createRequestBody(options: UploaderOptions, decorator: RequestBodyDecorator, file: File): RequestBody {
118
+ private fun createRequestBody(
119
+ options: UploaderOptions,
120
+ decorator: RequestBodyDecorator,
121
+ file: File
122
+ ): RequestBody {
105
123
  return when (options.uploadType) {
106
124
  UploadType.BINARY_CONTENT -> {
107
125
  val mimeType: String? = if (options.mimeType?.isNotEmpty() == true) {
@@ -122,7 +140,11 @@ class Uploader(private val reactContext: ReactApplicationContext) {
122
140
  val mimeType: String = options.mimeType ?: URLConnection.guessContentTypeFromName(file.name)
123
141
 
124
142
  val fieldName = options.fieldName ?: file.name
125
- bodyBuilder.addFormDataPart(fieldName, file.name, decorator.decorate(file.asRequestBody(mimeType.toMediaTypeOrNull())))
143
+ bodyBuilder.addFormDataPart(
144
+ fieldName,
145
+ file.name,
146
+ decorator.decorate(file.asRequestBody(mimeType.toMediaTypeOrNull()))
147
+ )
126
148
  bodyBuilder.build()
127
149
  }
128
150
  }
@@ -175,4 +197,19 @@ class Uploader(private val reactContext: ReactApplicationContext) {
175
197
  }
176
198
  return responseHeaders
177
199
  }
200
+
201
+ fun cancelUpload(uuid:String,shouldCancelAll:Boolean) {
202
+ if(shouldCancelAll)
203
+ {
204
+ httpCallManager.cancelAllTasks()
205
+ }
206
+ else if(uuid=="")
207
+ {
208
+ httpCallManager.taskPop()?.cancel()
209
+ }
210
+ else
211
+ {
212
+ httpCallManager.uploadTaskForId(uuid)?.cancel()
213
+ }
214
+ }
178
215
  }
@@ -8,7 +8,6 @@ import android.net.Uri
8
8
  import android.os.Build
9
9
  import android.text.TextUtils
10
10
  import android.webkit.URLUtil
11
- import androidx.annotation.RequiresApi
12
11
  import com.facebook.react.bridge.Arguments
13
12
  import com.facebook.react.bridge.GuardedResultAsyncTask
14
13
  import com.facebook.react.bridge.Promise
@@ -39,7 +38,6 @@ class CreateVideoThumbnailClass(private val reactContext: ReactApplicationContex
39
38
  weakContext = WeakReference(reactContext.applicationContext)
40
39
  }
41
40
 
42
- @RequiresApi(Build.VERSION_CODES.N)
43
41
  override fun doInBackgroundGuarded(): ReadableMap? {
44
42
  val format = "jpeg"
45
43
  val cacheName = if (options.hasKey("cacheName")) options.getString("cacheName") else ""
@@ -23,6 +23,7 @@ abstract class CompressorSpec(context: ReactApplicationContext?) : ReactContextB
23
23
  abstract fun compress(fileUrl: String, optionMap: ReadableMap, promise: Promise)
24
24
  abstract fun cancelCompression(uuid: String)
25
25
  abstract fun upload(fileUrl: String, options: ReadableMap, promise: Promise)
26
+ abstract fun cancelUpload(uuid: String, shouldCancelAll:Boolean)
26
27
 
27
28
  abstract fun download(fileUrl: String, options: ReadableMap, promise: Promise)
28
29
  abstract fun activateBackgroundTask(options: ReadableMap, promise: Promise)