react-native-compressor 1.18.2 → 2.0.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 (141) hide show
  1. package/android/CMakeLists.txt +27 -0
  2. package/android/build.gradle +56 -58
  3. package/android/gradle.properties +5 -5
  4. package/android/src/main/AndroidManifestNew.xml +3 -0
  5. package/android/src/main/cpp/cpp-adapter.cpp +8 -0
  6. package/android/src/main/java/com/margelo/nitro/compressor/HybridCompressor.kt +213 -0
  7. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.kt +41 -21
  8. package/android/src/main/java/com/reactnativecompressor/NitroCompressorPackage.kt +30 -0
  9. package/android/src/main/java/com/reactnativecompressor/NitroPromiseAdapter.kt +55 -0
  10. package/android/src/main/java/com/reactnativecompressor/Utils/EventEmitterHandler.kt +49 -45
  11. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +1 -1
  12. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt +1 -1
  13. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressionProfile.kt +21 -11
  14. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt +311 -76
  15. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/utils/CompressorUtils.kt +96 -5
  16. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/utils/LocationExtractor.kt +397 -0
  17. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/videoHelpers/LocationBox.kt +47 -0
  18. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/videoHelpers/MP4Builder.kt +39 -7
  19. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/videoHelpers/Mp4Movie.kt +7 -0
  20. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/videoHelpers/OutputSurface.kt +30 -4
  21. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt +28 -2
  22. package/ios/Audio/FormatConverter/FormatConverter+Compressed.swift +1 -1
  23. package/ios/Audio/FormatConverter/FormatConverter+Utilities.swift +1 -1
  24. package/ios/Audio/FormatConverter/FormatConverter.swift +5 -3
  25. package/ios/HybridCompressor.swift +247 -0
  26. package/ios/Image/ImageCompressor.swift +8 -2
  27. package/ios/Utils/EventEmitterHandler.swift +56 -34
  28. package/ios/Video/NextLevelSessionExporter.swift +43 -8
  29. package/ios/Video/VideoMain.swift +44 -14
  30. package/lib/commonjs/Audio/index.js +1 -1
  31. package/lib/commonjs/Audio/index.js.map +1 -1
  32. package/lib/commonjs/Image/index.js +2 -22
  33. package/lib/commonjs/Image/index.js.map +1 -1
  34. package/lib/commonjs/Main.js +8 -8
  35. package/lib/commonjs/Main.js.map +1 -1
  36. package/lib/commonjs/Video/index.js +25 -65
  37. package/lib/commonjs/Video/index.js.map +1 -1
  38. package/lib/commonjs/specs/Compressor.nitro.js +6 -0
  39. package/lib/commonjs/specs/Compressor.nitro.js.map +1 -0
  40. package/lib/commonjs/utils/Downloader.js +8 -24
  41. package/lib/commonjs/utils/Downloader.js.map +1 -1
  42. package/lib/commonjs/utils/Uploader.js +3 -18
  43. package/lib/commonjs/utils/Uploader.js.map +1 -1
  44. package/lib/commonjs/utils/helpers.js +18 -1
  45. package/lib/commonjs/utils/helpers.js.map +1 -1
  46. package/lib/commonjs/utils/index.js +13 -13
  47. package/lib/commonjs/utils/index.js.map +1 -1
  48. package/lib/module/Audio/index.js +2 -2
  49. package/lib/module/Audio/index.js.map +1 -1
  50. package/lib/module/Image/index.js +3 -23
  51. package/lib/module/Image/index.js.map +1 -1
  52. package/lib/module/Main.js +9 -9
  53. package/lib/module/Main.js.map +1 -1
  54. package/lib/module/Video/index.js +26 -66
  55. package/lib/module/Video/index.js.map +1 -1
  56. package/lib/module/specs/Compressor.nitro.js +4 -0
  57. package/lib/module/specs/Compressor.nitro.js.map +1 -0
  58. package/lib/module/utils/Downloader.js +10 -26
  59. package/lib/module/utils/Downloader.js.map +1 -1
  60. package/lib/module/utils/Uploader.js +5 -20
  61. package/lib/module/utils/Uploader.js.map +1 -1
  62. package/lib/module/utils/helpers.js +16 -0
  63. package/lib/module/utils/helpers.js.map +1 -1
  64. package/lib/module/utils/index.js +2 -1
  65. package/lib/module/utils/index.js.map +1 -1
  66. package/lib/typescript/src/Image/index.d.ts.map +1 -1
  67. package/lib/typescript/src/Main.d.ts +2 -1
  68. package/lib/typescript/src/Main.d.ts.map +1 -1
  69. package/lib/typescript/src/Video/index.d.ts +1 -1
  70. package/lib/typescript/src/Video/index.d.ts.map +1 -1
  71. package/lib/typescript/src/index.d.ts.map +1 -1
  72. package/lib/typescript/src/specs/Compressor.nitro.d.ts +44 -0
  73. package/lib/typescript/src/specs/Compressor.nitro.d.ts.map +1 -0
  74. package/lib/typescript/src/utils/Downloader.d.ts.map +1 -1
  75. package/lib/typescript/src/utils/Uploader.d.ts.map +1 -1
  76. package/lib/typescript/src/utils/helpers.d.ts +7 -0
  77. package/lib/typescript/src/utils/helpers.d.ts.map +1 -1
  78. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  79. package/nitrogen/generated/android/NitroCompressor+autolinking.cmake +81 -0
  80. package/nitrogen/generated/android/NitroCompressor+autolinking.gradle +27 -0
  81. package/nitrogen/generated/android/NitroCompressorOnLoad.cpp +60 -0
  82. package/nitrogen/generated/android/NitroCompressorOnLoad.hpp +34 -0
  83. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  84. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +75 -0
  85. package/nitrogen/generated/android/c++/JFunc_void_double_double.hpp +75 -0
  86. package/nitrogen/generated/android/c++/JHybridCompressorSpec.cpp +293 -0
  87. package/nitrogen/generated/android/c++/JHybridCompressorSpec.hpp +78 -0
  88. package/nitrogen/generated/android/c++/JVideoThumbnailResult.hpp +73 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/Func_void.kt +80 -0
  90. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/Func_void_double.kt +80 -0
  91. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/Func_void_double_double.kt +80 -0
  92. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/HybridCompressorSpec.kt +141 -0
  93. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/NitroCompressorOnLoad.kt +35 -0
  94. package/nitrogen/generated/android/kotlin/com/margelo/nitro/compressor/VideoThumbnailResult.kt +71 -0
  95. package/nitrogen/generated/ios/c++/HybridCompressorSpecSwift.cpp +11 -0
  96. package/nitrogen/generated/ios/c++/HybridCompressorSpecSwift.hpp +204 -0
  97. package/nitrogen/generated/ios/react_native_compressor+autolinking.rb +62 -0
  98. package/nitrogen/generated/ios/react_native_compressor-Swift-Cxx-Bridge.cpp +89 -0
  99. package/nitrogen/generated/ios/react_native_compressor-Swift-Cxx-Bridge.hpp +337 -0
  100. package/nitrogen/generated/ios/react_native_compressor-Swift-Cxx-Umbrella.hpp +51 -0
  101. package/nitrogen/generated/ios/react_native_compressorAutolinking.mm +33 -0
  102. package/nitrogen/generated/ios/react_native_compressorAutolinking.swift +26 -0
  103. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  104. package/nitrogen/generated/ios/swift/Func_void_VideoThumbnailResult.swift +46 -0
  105. package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
  106. package/nitrogen/generated/ios/swift/Func_void_double_double.swift +46 -0
  107. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  108. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_AnyMap_.swift +46 -0
  109. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  110. package/nitrogen/generated/ios/swift/HybridCompressorSpec.swift +70 -0
  111. package/nitrogen/generated/ios/swift/HybridCompressorSpec_cxx.swift +493 -0
  112. package/nitrogen/generated/ios/swift/VideoThumbnailResult.swift +49 -0
  113. package/nitrogen/generated/shared/c++/HybridCompressorSpec.cpp +36 -0
  114. package/nitrogen/generated/shared/c++/HybridCompressorSpec.hpp +83 -0
  115. package/nitrogen/generated/shared/c++/VideoThumbnailResult.hpp +99 -0
  116. package/package.json +8 -12
  117. package/react-native-compressor.podspec +6 -24
  118. package/src/Audio/index.tsx +2 -2
  119. package/src/Image/index.tsx +3 -26
  120. package/src/Main.tsx +14 -16
  121. package/src/Video/index.tsx +25 -77
  122. package/src/specs/Compressor.nitro.ts +56 -0
  123. package/src/utils/Downloader.tsx +8 -27
  124. package/src/utils/Uploader.tsx +12 -24
  125. package/src/utils/helpers.ts +18 -0
  126. package/src/utils/index.tsx +3 -2
  127. package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +0 -180
  128. package/android/src/main/java/com/reactnativecompressor/CompressorPackage.kt +0 -34
  129. package/android/src/newarch/CompressorSpec.kt +0 -5
  130. package/android/src/oldarch/CompressorSpec.kt +0 -36
  131. package/ios/Compressor-Bridging-Header.h +0 -6
  132. package/ios/Compressor.h +0 -5
  133. package/ios/Compressor.mm +0 -82
  134. package/ios/CompressorManager.swift +0 -117
  135. package/lib/commonjs/Spec/NativeCompressor.js +0 -9
  136. package/lib/commonjs/Spec/NativeCompressor.js.map +0 -1
  137. package/lib/module/Spec/NativeCompressor.js +0 -5
  138. package/lib/module/Spec/NativeCompressor.js.map +0 -1
  139. package/lib/typescript/src/Spec/NativeCompressor.d.ts +0 -30
  140. package/lib/typescript/src/Spec/NativeCompressor.d.ts.map +0 -1
  141. package/src/Spec/NativeCompressor.ts +0 -41
@@ -0,0 +1,99 @@
1
+ ///
2
+ /// VideoThumbnailResult.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+ #include <string>
34
+
35
+ namespace margelo::nitro::compressor {
36
+
37
+ /**
38
+ * A struct which can be represented as a JavaScript object (VideoThumbnailResult).
39
+ */
40
+ struct VideoThumbnailResult final {
41
+ public:
42
+ std::string path SWIFT_PRIVATE;
43
+ double size SWIFT_PRIVATE;
44
+ std::string mime SWIFT_PRIVATE;
45
+ double width SWIFT_PRIVATE;
46
+ double height SWIFT_PRIVATE;
47
+
48
+ public:
49
+ VideoThumbnailResult() = default;
50
+ explicit VideoThumbnailResult(std::string path, double size, std::string mime, double width, double height): path(path), size(size), mime(mime), width(width), height(height) {}
51
+
52
+ public:
53
+ friend bool operator==(const VideoThumbnailResult& lhs, const VideoThumbnailResult& rhs) = default;
54
+ };
55
+
56
+ } // namespace margelo::nitro::compressor
57
+
58
+ namespace margelo::nitro {
59
+
60
+ // C++ VideoThumbnailResult <> JS VideoThumbnailResult (object)
61
+ template <>
62
+ struct JSIConverter<margelo::nitro::compressor::VideoThumbnailResult> final {
63
+ static inline margelo::nitro::compressor::VideoThumbnailResult fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
64
+ jsi::Object obj = arg.asObject(runtime);
65
+ return margelo::nitro::compressor::VideoThumbnailResult(
66
+ JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path"))),
67
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "size"))),
68
+ JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "mime"))),
69
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
70
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))
71
+ );
72
+ }
73
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::compressor::VideoThumbnailResult& arg) {
74
+ jsi::Object obj(runtime);
75
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "path"), JSIConverter<std::string>::toJSI(runtime, arg.path));
76
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "size"), JSIConverter<double>::toJSI(runtime, arg.size));
77
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "mime"), JSIConverter<std::string>::toJSI(runtime, arg.mime));
78
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
79
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
80
+ return obj;
81
+ }
82
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
83
+ if (!value.isObject()) {
84
+ return false;
85
+ }
86
+ jsi::Object obj = value.getObject(runtime);
87
+ if (!nitro::isPlainObject(runtime, obj)) {
88
+ return false;
89
+ }
90
+ if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path")))) return false;
91
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "size")))) return false;
92
+ if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "mime")))) return false;
93
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
94
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
95
+ return true;
96
+ }
97
+ };
98
+
99
+ } // namespace margelo::nitro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-compressor",
3
- "version": "1.18.2",
3
+ "version": "2.0.0",
4
4
  "description": "Compress Image, Video, and Audio same like Whatsapp & Auto/Manual Compression | Background Upload | Download File | Create Video Thumbnail",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -13,6 +13,7 @@
13
13
  "android",
14
14
  "ios",
15
15
  "cpp",
16
+ "nitrogen",
16
17
  "app.plugin.js",
17
18
  "*.podspec",
18
19
  "!lib/typescript/example",
@@ -34,7 +35,8 @@
34
35
  "test:harness:ios": "cd examples/bare && react-native-harness --config ./jest.harness.config.mjs --harnessRunner ios --verbose",
35
36
  "typecheck": "tsc --noEmit",
36
37
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
37
- "prepack": "bob build",
38
+ "nitrogen": "nitrogen",
39
+ "prepack": "nitrogen && bob build",
38
40
  "release": "release-it",
39
41
  "example:bare": "yarn workspace react-native-compressor-bare-example",
40
42
  "example:expo": "yarn workspace react-native-compressor-expo-example",
@@ -106,18 +108,21 @@
106
108
  "eslint-plugin-prettier": "^5.5.5",
107
109
  "jest": "^30.3.0",
108
110
  "lefthook": "^2.1.4",
111
+ "nitrogen": "^0.35.9",
109
112
  "prettier": "^3.8.1",
110
113
  "react": "19.2.3",
111
114
  "react-native": "0.85.0",
112
115
  "react-native-builder-bob": "^0.41.0",
113
116
  "react-native-harness": "1.1.0",
117
+ "react-native-nitro-modules": "^0.35.9",
114
118
  "release-it": "^19.2.4",
115
119
  "turbo": "^2.8.21",
116
120
  "typescript": "^6.0.2"
117
121
  },
118
122
  "peerDependencies": {
119
123
  "react": "*",
120
- "react-native": "*"
124
+ "react-native": "*",
125
+ "react-native-nitro-modules": ">=0.35.0"
121
126
  },
122
127
  "engines": {
123
128
  "node": ">= 22.11.0"
@@ -136,15 +141,6 @@
136
141
  ]
137
142
  ]
138
143
  },
139
- "codegenConfig": {
140
- "libraries": [
141
- {
142
- "name": "RNCompressorSpec",
143
- "type": "modules",
144
- "jsSrcsDir": "src"
145
- }
146
- ]
147
- },
148
144
  "workspaces": [
149
145
  "examples/*"
150
146
  ],
@@ -1,7 +1,6 @@
1
1
  require "json"
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
- folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
4
 
6
5
  Pod::Spec.new do |s|
7
6
  s.name = "react-native-compressor"
@@ -11,32 +10,15 @@ Pod::Spec.new do |s|
11
10
  s.license = package["license"]
12
11
  s.authors = package["author"]
13
12
 
14
- s.platforms = { :ios => "11.0" }
13
+ s.platforms = { :ios => "13.4" }
15
14
  s.source = { :git => "https://github.com/numandev1/react-native-compressor.git", :tag => "#{s.version}" }
16
15
 
17
16
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
17
 
19
- s.dependency "React-Core"
20
- # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
21
- # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
22
- if respond_to?(:install_modules_dependencies, true)
23
- install_modules_dependencies(s)
24
- else
25
- s.dependency "React-Core"
18
+ # Add all files generated by Nitrogen + the NitroModules dependency.
19
+ load File.join(__dir__, 'nitrogen', 'generated', 'ios', 'react_native_compressor+autolinking.rb')
20
+ add_nitrogen_files(s)
26
21
 
27
- # Don't install the dependencies when we run `pod install` in the old architecture.
28
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
29
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
30
- s.pod_target_xcconfig = {
31
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
32
- "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
33
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
34
- }
35
- s.dependency "React-Codegen"
36
- s.dependency "RCT-Folly"
37
- s.dependency "RCTRequired"
38
- s.dependency "RCTTypeSafety"
39
- s.dependency "ReactCommon/turbomodule/core"
40
- end
41
- end
22
+ s.dependency "React-Core"
23
+ install_modules_dependencies(s)
42
24
  end
@@ -1,13 +1,13 @@
1
1
  import { Compressor } from '../Main';
2
2
 
3
- import { DEFAULT_COMPRESS_AUDIO_OPTIONS } from '../utils';
3
+ import { DEFAULT_COMPRESS_AUDIO_OPTIONS, toNativeOptions } from '../utils';
4
4
  import type { AudioType } from '../utils';
5
5
  const NativeAudio = Compressor;
6
6
 
7
7
  const Audio: AudioType = {
8
8
  compress: async (url, options = DEFAULT_COMPRESS_AUDIO_OPTIONS) => {
9
9
  try {
10
- return NativeAudio.compress_audio(url, options);
10
+ return NativeAudio.compress_audio(url, toNativeOptions(options));
11
11
  } catch (error: any) {
12
12
  throw error.message;
13
13
  }
@@ -1,8 +1,6 @@
1
1
  import { Compressor } from '../Main';
2
- import { uuidv4 } from '../utils';
2
+ import { toNativeOptions } from '../utils';
3
3
  const base64UrlRegex = /^data:image\/.*;(?:charset=.{3,5};)?base64,/;
4
- import type { NativeEventSubscription } from 'react-native';
5
- import { NativeEventEmitter } from 'react-native';
6
4
 
7
5
  export type InputType = 'base64' | 'uri';
8
6
 
@@ -55,8 +53,6 @@ export type CompressorOptions = {
55
53
  progressDivider?: number;
56
54
  };
57
55
 
58
- const ImageCompressEventEmitter = new NativeEventEmitter(Compressor);
59
-
60
56
  const NativeImage = Compressor;
61
57
 
62
58
  type ImageType = {
@@ -69,27 +65,8 @@ const Image: ImageType = {
69
65
  throw new Error('Compression value is empty, please provide a value for compression.');
70
66
  }
71
67
 
72
- let subscription: NativeEventSubscription;
73
- try {
74
- if (options?.downloadProgress) {
75
- const uuid = uuidv4();
76
- //@ts-ignore
77
- options.uuid = uuid;
78
- subscription = ImageCompressEventEmitter.addListener('downloadProgress', (event: any) => {
79
- if (event.uuid === uuid) {
80
- options.downloadProgress && options.downloadProgress(event.data.progress);
81
- }
82
- });
83
- }
84
-
85
- const cleanData = value.replace(base64UrlRegex, '');
86
- return await NativeImage.image_compress(cleanData, options);
87
- } finally {
88
- // @ts-ignore
89
- if (subscription) {
90
- subscription.remove();
91
- }
92
- }
68
+ const cleanData = value.replace(base64UrlRegex, '');
69
+ return await NativeImage.image_compress(cleanData, toNativeOptions(options), options.downloadProgress);
93
70
  },
94
71
  };
95
72
 
package/src/Main.tsx CHANGED
@@ -1,25 +1,23 @@
1
- import { NativeModules, Platform } from 'react-native';
1
+ import { Platform } from 'react-native';
2
+ import { NitroModules } from 'react-native-nitro-modules';
3
+
4
+ import type { Compressor as CompressorSpec } from './specs/Compressor.nitro';
2
5
 
3
6
  const LINKING_ERROR =
4
7
  `The package 'react-native-compressor' doesn't seem to be linked. Make sure: \n\n` +
5
8
  Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
9
  '- You rebuilt the app after installing the package\n' +
7
- '- You are not using Expo Go\n';
8
-
9
- // @ts-expect-error
10
- const isTurboModuleEnabled = global.__turboModuleProxy != null;
10
+ '- You are not using Expo Go\n' +
11
+ '- You have installed `react-native-nitro-modules`\n';
11
12
 
12
- const CompressorModule = isTurboModuleEnabled ? require('./Spec/NativeCompressor').default : NativeModules.Compressor;
13
+ const createCompressor = (): CompressorSpec => {
14
+ try {
15
+ return NitroModules.createHybridObject<CompressorSpec>('Compressor');
16
+ } catch {
17
+ throw new Error(LINKING_ERROR);
18
+ }
19
+ };
13
20
 
14
- const Compressor = CompressorModule
15
- ? CompressorModule
16
- : new Proxy(
17
- {},
18
- {
19
- get() {
20
- throw new Error(LINKING_ERROR);
21
- },
22
- },
23
- );
21
+ const Compressor = createCompressor();
24
22
 
25
23
  export { Compressor };
@@ -1,7 +1,5 @@
1
- import { NativeEventEmitter } from 'react-native';
2
- import type { NativeEventSubscription } from 'react-native';
3
1
  import { Compressor } from '../Main';
4
- import { uuidv4 } from '../utils';
2
+ import { toNativeOptions, uuidv4 } from '../utils';
5
3
 
6
4
  export type compressionMethod = 'auto' | 'manual';
7
5
  type videoCompresssionType = {
@@ -29,8 +27,6 @@ export type VideoCompressorType = {
29
27
  deactivateBackgroundTask(): Promise<any>;
30
28
  };
31
29
 
32
- const VideoCompressEventEmitter = new NativeEventEmitter(Compressor);
33
-
34
30
  const NativeVideoCompressor = Compressor;
35
31
 
36
32
  export const cancelCompression = (cancellationId: string) => {
@@ -40,85 +36,37 @@ export const cancelCompression = (cancellationId: string) => {
40
36
  const Video: VideoCompressorType = {
41
37
  compress: async (fileUrl: string, options?: videoCompresssionType, onProgress?: (progress: number) => void) => {
42
38
  const uuid = uuidv4();
43
- let subscription: NativeEventSubscription;
44
- let subscription2: NativeEventSubscription;
45
-
46
- try {
47
- if (onProgress) {
48
- subscription = VideoCompressEventEmitter.addListener('videoCompressProgress', (event: any) => {
49
- if (event.uuid === uuid) {
50
- onProgress(event.data.progress);
51
- }
52
- });
53
- }
54
-
55
- if (options?.downloadProgress) {
56
- //@ts-ignore
57
- subscription2 = VideoCompressEventEmitter.addListener('downloadProgress', (event: any) => {
58
- if (event.uuid === uuid) {
59
- options.downloadProgress && options.downloadProgress(event.data.progress);
60
- }
61
- });
62
- }
63
39
 
64
- const modifiedOptions: {
65
- uuid: string;
66
- bitrate?: number;
67
- compressionMethod?: compressionMethod;
68
- maxSize?: number;
69
- minimumFileSizeForCompress?: number;
70
- progressDivider?: number;
71
- stripAudio?: boolean;
72
- } = { uuid };
73
- if (options?.progressDivider) modifiedOptions.progressDivider = options?.progressDivider;
74
- if (options?.bitrate) modifiedOptions.bitrate = options?.bitrate;
75
- if (options?.compressionMethod) {
76
- modifiedOptions.compressionMethod = options?.compressionMethod;
77
- } else {
78
- modifiedOptions.compressionMethod = 'auto';
79
- }
80
- if (options?.maxSize) {
81
- modifiedOptions.maxSize = options?.maxSize;
82
- } else {
83
- modifiedOptions.maxSize = 640;
84
- }
85
- if (options?.minimumFileSizeForCompress !== undefined) {
86
- modifiedOptions.minimumFileSizeForCompress = options?.minimumFileSizeForCompress;
87
- }
88
- if (options?.stripAudio) {
89
- modifiedOptions.stripAudio = options.stripAudio;
90
- }
91
- if (options?.getCancellationId) {
92
- options?.getCancellationId(uuid);
93
- }
94
-
95
- const result = await NativeVideoCompressor.compress(fileUrl, modifiedOptions);
96
- return result;
97
- } finally {
98
- // @ts-ignore
99
- if (subscription) {
100
- subscription.remove();
101
- }
102
- //@ts-ignore
103
- if (subscription2) {
104
- subscription2.remove();
105
- }
40
+ const modifiedOptions: Record<string, unknown> = { uuid };
41
+ if (options?.progressDivider) modifiedOptions.progressDivider = options?.progressDivider;
42
+ if (options?.bitrate) modifiedOptions.bitrate = options?.bitrate;
43
+ if (options?.compressionMethod) {
44
+ modifiedOptions.compressionMethod = options?.compressionMethod;
45
+ } else {
46
+ modifiedOptions.compressionMethod = 'auto';
47
+ }
48
+ if (options?.maxSize) {
49
+ modifiedOptions.maxSize = options?.maxSize;
50
+ } else {
51
+ modifiedOptions.maxSize = 640;
106
52
  }
53
+ if (options?.minimumFileSizeForCompress !== undefined) {
54
+ modifiedOptions.minimumFileSizeForCompress = options?.minimumFileSizeForCompress;
55
+ }
56
+ if (options?.stripAudio) {
57
+ modifiedOptions.stripAudio = options.stripAudio;
58
+ }
59
+ if (options?.getCancellationId) {
60
+ options?.getCancellationId(uuid);
61
+ }
62
+
63
+ return NativeVideoCompressor.compress(fileUrl, toNativeOptions(modifiedOptions), onProgress, options?.downloadProgress);
107
64
  },
108
65
  cancelCompression,
109
66
  activateBackgroundTask(onExpired?) {
110
- if (onExpired) {
111
- const subscription: NativeEventSubscription = VideoCompressEventEmitter.addListener('backgroundTaskExpired', (event: any) => {
112
- onExpired(event);
113
- if (subscription) {
114
- subscription.remove();
115
- }
116
- });
117
- }
118
- return NativeVideoCompressor.activateBackgroundTask({});
67
+ return NativeVideoCompressor.activateBackgroundTask({}, onExpired ? () => onExpired(undefined) : undefined);
119
68
  },
120
69
  deactivateBackgroundTask() {
121
- VideoCompressEventEmitter.removeAllListeners('backgroundTaskExpired');
122
70
  return NativeVideoCompressor.deactivateBackgroundTask({});
123
71
  },
124
72
  } as VideoCompressorType;
@@ -0,0 +1,56 @@
1
+ import type { AnyMap, HybridObject } from 'react-native-nitro-modules';
2
+
3
+ export interface VideoThumbnailResult {
4
+ path: string;
5
+ size: number;
6
+ mime: string;
7
+ width: number;
8
+ height: number;
9
+ }
10
+
11
+ /**
12
+ * Nitro HybridObject spec for the single native `Compressor` module.
13
+ *
14
+ * Notes on the migration from the old TurboModule spec:
15
+ * - Progress is delivered through callback parameters (`onProgress` / `onDownloadProgress` /
16
+ * `onExpired`) instead of `NativeEventEmitter` events. Callbacks can't live inside an `AnyMap`,
17
+ * so any progress callback that used to be nested in the options object is now a top-level param.
18
+ * - `optionMap`/`options` stay untyped (`AnyMap`) and are parsed natively, exactly as before.
19
+ * - `getImageMetaData` / `getVideoMetaData` / `upload` resolve objects at runtime (EXIF map /
20
+ * metadata map / `{status,headers,body}`), so they return `AnyMap` — the old `Promise<string>`
21
+ * typing was lossy.
22
+ * - `uuid` is still threaded inside the options map for cancellation (`cancelCompression` /
23
+ * `cancelUpload`) and for routing native progress emissions to the registered callback.
24
+ */
25
+ export interface Compressor extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
26
+ // Image
27
+ image_compress(imagePath: string, optionMap: AnyMap, onDownloadProgress?: (progress: number) => void): Promise<string>;
28
+ getImageMetaData(filePath: string): Promise<AnyMap>;
29
+
30
+ // Video
31
+ compress(
32
+ fileUrl: string,
33
+ optionMap: AnyMap,
34
+ onProgress?: (progress: number) => void,
35
+ onDownloadProgress?: (progress: number) => void,
36
+ ): Promise<string>;
37
+ cancelCompression(uuid: string): void;
38
+ getVideoMetaData(filePath: string): Promise<AnyMap>;
39
+ activateBackgroundTask(options: AnyMap, onExpired?: () => void): Promise<string>;
40
+ deactivateBackgroundTask(options: AnyMap): Promise<string>;
41
+
42
+ // Audio
43
+ compress_audio(fileUrl: string, optionMap: AnyMap): Promise<string>;
44
+
45
+ // Upload / Download
46
+ upload(fileUrl: string, options: AnyMap, onProgress?: (written: number, total: number) => void): Promise<AnyMap>;
47
+ cancelUpload(uuid: string, shouldCancelAll: boolean): void;
48
+ download(fileUrl: string, options: AnyMap, onProgress?: (progress: number) => void): Promise<string>;
49
+
50
+ // Others
51
+ generateFilePath(fileExtension: string): Promise<string>;
52
+ getRealPath(path: string, type: string): Promise<string>;
53
+ getFileSize(filePath: string): Promise<string>;
54
+ createVideoThumbnail(fileUrl: string, options: AnyMap): Promise<VideoThumbnailResult>;
55
+ clearCache(cacheDir?: string): Promise<string>;
56
+ }
@@ -1,31 +1,12 @@
1
- import { NativeEventEmitter, Platform } from 'react-native';
2
- import type { NativeEventSubscription } from 'react-native';
1
+ import { Platform } from 'react-native';
3
2
  import { Compressor } from '../Main';
4
- const CompressEventEmitter = new NativeEventEmitter(Compressor);
5
- import { uuidv4 } from './helpers';
3
+ import { toNativeOptions, uuidv4 } from './helpers';
4
+
6
5
  export const download = async (fileUrl: string, downloadProgress?: (progress: number) => void, progressDivider?: number): Promise<any> => {
7
- let subscription: NativeEventSubscription;
8
- try {
9
- const uuid = uuidv4();
10
- if (downloadProgress) {
11
- subscription = CompressEventEmitter.addListener('downloadProgress', (event: any) => {
12
- if (event.uuid === uuid) {
13
- downloadProgress(event.data.progress);
14
- }
15
- });
16
- }
17
- if (Platform.OS === 'android' && fileUrl.includes('file://')) {
18
- fileUrl = fileUrl.replace('file://', '');
19
- }
20
- const result = await Compressor.download(fileUrl, {
21
- uuid,
22
- progressDivider,
23
- });
24
- return result;
25
- } finally {
26
- // @ts-ignore
27
- if (subscription) {
28
- subscription.remove();
29
- }
6
+ const uuid = uuidv4();
7
+ if (Platform.OS === 'android' && fileUrl.includes('file://')) {
8
+ fileUrl = fileUrl.replace('file://', '');
30
9
  }
10
+ const result = await Compressor.download(fileUrl, toNativeOptions({ uuid, progressDivider }), downloadProgress);
11
+ return result;
31
12
  };
@@ -1,8 +1,6 @@
1
- import { NativeEventEmitter, Platform } from 'react-native';
2
- import type { NativeEventSubscription } from 'react-native';
1
+ import { Platform } from 'react-native';
3
2
  import { Compressor } from '../Main';
4
- const CompressEventEmitter = new NativeEventEmitter(Compressor);
5
- import { uuidv4 } from './helpers';
3
+ import { toNativeOptions, uuidv4 } from './helpers';
6
4
  export enum UploadType {
7
5
  BINARY_CONTENT = 0,
8
6
  MULTIPART = 1,
@@ -51,15 +49,7 @@ export const backgroundUpload = async (
51
49
  abortSignal?: AbortSignal,
52
50
  ): Promise<any> => {
53
51
  const uuid = uuidv4();
54
- let subscription: NativeEventSubscription;
55
52
  try {
56
- if (onProgress) {
57
- subscription = CompressEventEmitter.addListener('uploadProgress', (event: any) => {
58
- if (event.uuid === uuid) {
59
- onProgress(event.data.written, event.data.total);
60
- }
61
- });
62
- }
63
53
  if (Platform.OS === 'android' && fileUrl.includes('file://')) {
64
54
  fileUrl = fileUrl.replace('file://', '');
65
55
  }
@@ -70,20 +60,18 @@ export const backgroundUpload = async (
70
60
 
71
61
  abortSignal?.addEventListener('abort', () => cancelUpload(uuid));
72
62
 
73
- const result = await Compressor.upload(fileUrl, {
74
- uuid,
75
- method: options.httpMethod,
76
- headers: options.headers,
77
- uploadType: options.uploadType,
78
- ...options,
79
- url,
80
- });
63
+ const result = await Compressor.upload(
64
+ fileUrl,
65
+ toNativeOptions({
66
+ ...options,
67
+ uuid,
68
+ method: options.httpMethod,
69
+ url,
70
+ }),
71
+ onProgress,
72
+ );
81
73
  return result;
82
74
  } finally {
83
- // @ts-ignore
84
- if (subscription) {
85
- subscription.remove();
86
- }
87
75
  abortSignal?.removeEventListener('abort', () => cancelUpload(uuid));
88
76
  }
89
77
  };
@@ -1,3 +1,5 @@
1
+ import type { AnyMap } from 'react-native-nitro-modules';
2
+
1
3
  export const uuidv4 = () => {
2
4
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
3
5
  const r = (parseFloat('0.' + Math.random().toString().replace('0.', '') + new Date().getTime()) * 16) | 0,
@@ -6,3 +8,19 @@ export const uuidv4 = () => {
6
8
  return v.toString(16);
7
9
  });
8
10
  };
11
+
12
+ /**
13
+ * Build a Nitro-safe options map. Nitro's `AnyMap` converter throws when it
14
+ * encounters a `undefined` or function-valued property, so we drop both —
15
+ * progress callbacks are passed as separate native method parameters now.
16
+ */
17
+ export const toNativeOptions = (options: Record<string, unknown>): AnyMap => {
18
+ const result: Record<string, unknown> = {};
19
+ for (const key of Object.keys(options)) {
20
+ const value = options[key];
21
+ if (value !== undefined && typeof value !== 'function') {
22
+ result[key] = value;
23
+ }
24
+ }
25
+ return result as AnyMap;
26
+ };
@@ -1,5 +1,6 @@
1
1
  import { Compressor } from '../Main';
2
2
  import { Platform } from 'react-native';
3
+ import { toNativeOptions } from './helpers';
3
4
  type qualityType = 'low' | 'medium' | 'high';
4
5
  const INCORRECT_INPUT_PATH = 'Incorrect input path. Please provide a valid one';
5
6
 
@@ -72,7 +73,7 @@ export const getRealPath: getRealPathType = (path, type = 'video') => {
72
73
  };
73
74
 
74
75
  export const getVideoMetaData: getVideoMetaDataType = (path: string) => {
75
- return Compressor.getVideoMetaData(path);
76
+ return Compressor.getVideoMetaData(path) as ReturnType<getVideoMetaDataType>;
76
77
  };
77
78
 
78
79
  const unifyMetaData = (exifResult: any) => {
@@ -96,7 +97,7 @@ export const getImageMetaData: getImageMetaDataType = async (path: string) => {
96
97
  };
97
98
 
98
99
  export const createVideoThumbnail: createVideoThumbnailType = (fileUrl, options = {}) => {
99
- return Compressor.createVideoThumbnail(fileUrl, options);
100
+ return Compressor.createVideoThumbnail(fileUrl, toNativeOptions(options));
100
101
  };
101
102
 
102
103
  export const clearCache: clearCacheType = (cacheDir?: string) => {