Bluesky app fork with some witchin' additions 💫

Merge branch 'main' of https://github.com/bluesky-social/social-app

+516
patches/react-native-compressor+1.13.0.patch
··· 1 + diff --git a/node_modules/react-native-compressor/android/build.gradle b/node_modules/react-native-compressor/android/build.gradle 2 + index 5071139..84bee34 100644 3 + --- a/node_modules/react-native-compressor/android/build.gradle 4 + +++ b/node_modules/react-native-compressor/android/build.gradle 5 + @@ -115,7 +115,6 @@ dependencies { 6 + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" 7 + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" 8 + implementation 'org.mp4parser:isoparser:1.9.56' 9 + - implementation 'com.github.banketree:AndroidLame-kotlin:v0.0.1' 10 + implementation 'javazoom:jlayer:1.0.1' 11 + } 12 + 13 + diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt 14 + deleted file mode 100644 15 + index 9292d3e..0000000 16 + --- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt 17 + +++ /dev/null 18 + @@ -1,264 +0,0 @@ 19 + -package com.reactnativecompressor.Audio 20 + - 21 + - 22 + -import android.annotation.SuppressLint 23 + -import com.facebook.react.bridge.Promise 24 + -import com.facebook.react.bridge.ReactApplicationContext 25 + -import com.facebook.react.bridge.ReadableMap 26 + -import com.naman14.androidlame.LameBuilder 27 + -import com.naman14.androidlame.WaveReader 28 + -import com.reactnativecompressor.Utils.MediaCache 29 + -import com.reactnativecompressor.Utils.Utils 30 + -import com.reactnativecompressor.Utils.Utils.addLog 31 + -import javazoom.jl.converter.Converter 32 + -import javazoom.jl.decoder.JavaLayerException 33 + -import java.io.BufferedOutputStream 34 + -import java.io.File 35 + -import java.io.FileNotFoundException 36 + -import java.io.FileOutputStream 37 + -import java.io.IOException 38 + - 39 + -class AudioCompressor { 40 + - companion object { 41 + - val TAG="AudioMain" 42 + - private const val OUTPUT_STREAM_BUFFER = 8192 43 + - 44 + - var outputStream: BufferedOutputStream? = null 45 + - var waveReader: WaveReader? = null 46 + - @JvmStatic 47 + - fun CompressAudio( 48 + - fileUrl: String, 49 + - optionMap: ReadableMap, 50 + - context: ReactApplicationContext, 51 + - promise: Promise, 52 + - ) { 53 + - val realPath = Utils.getRealPath(fileUrl, context) 54 + - var _fileUrl=realPath 55 + - val filePathWithoutFileUri = realPath!!.replace("file://", "") 56 + - try { 57 + - var wavPath=filePathWithoutFileUri; 58 + - var isNonWav:Boolean=false 59 + - if (fileUrl.endsWith(".mp4", ignoreCase = true)) 60 + - { 61 + - addLog("mp4 file found") 62 + - val mp3Path= Utils.generateCacheFilePath("mp3", context) 63 + - AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false) 64 + - _fileUrl=Utils.slashifyFilePath(mp3Path) 65 + - wavPath= Utils.generateCacheFilePath("wav", context) 66 + - try { 67 + - val converter = Converter() 68 + - converter.convert(mp3Path, wavPath) 69 + - } catch (e: JavaLayerException) { 70 + - addLog("JavaLayerException error"+e.localizedMessage) 71 + - e.printStackTrace(); 72 + - } 73 + - isNonWav=true 74 + - } 75 + - else if (!fileUrl.endsWith(".wav", ignoreCase = true)) 76 + - { 77 + - addLog("non wav file found") 78 + - wavPath= Utils.generateCacheFilePath("wav", context) 79 + - try { 80 + - val converter = Converter() 81 + - converter.convert(filePathWithoutFileUri, wavPath) 82 + - } catch (e: JavaLayerException) { 83 + - addLog("JavaLayerException error"+e.localizedMessage) 84 + - e.printStackTrace(); 85 + - } 86 + - isNonWav=true 87 + - } 88 + - 89 + - 90 + - autoCompressHelper(wavPath,filePathWithoutFileUri, optionMap,context) { mp3Path, finished -> 91 + - if (finished) { 92 + - val returnableFilePath:String="file://$mp3Path" 93 + - addLog("finished: " + returnableFilePath) 94 + - MediaCache.removeCompletedImagePath(fileUrl) 95 + - if(isNonWav) 96 + - { 97 + - File(wavPath).delete() 98 + - } 99 + - promise.resolve(returnableFilePath) 100 + - } else { 101 + - addLog("error: "+mp3Path) 102 + - promise.resolve(_fileUrl) 103 + - } 104 + - } 105 + - } catch (e: Exception) { 106 + - promise.resolve(_fileUrl) 107 + - } 108 + - } 109 + - 110 + - @SuppressLint("WrongConstant") 111 + - private fun autoCompressHelper( 112 + - fileUrl: String, 113 + - actualFileUrl: String, 114 + - optionMap: ReadableMap, 115 + - context: ReactApplicationContext, 116 + - completeCallback: (String, Boolean) -> Unit 117 + - ) { 118 + - 119 + - val options = AudioHelper.fromMap(optionMap) 120 + - val quality = options.quality 121 + - 122 + - var isCompletedCallbackTriggered:Boolean=false 123 + - try { 124 + - var mp3Path = Utils.generateCacheFilePath("mp3", context) 125 + - val input = File(fileUrl) 126 + - val output = File(mp3Path) 127 + - 128 + - val CHUNK_SIZE = 8192 129 + - addLog("Initialising wav reader") 130 + - 131 + - waveReader = WaveReader(input) 132 + - 133 + - try { 134 + - waveReader!!.openWave() 135 + - } catch (e: IOException) { 136 + - e.printStackTrace() 137 + - } 138 + - 139 + - addLog("Intitialising encoder") 140 + - 141 + - 142 + - // for bitrate 143 + - var audioBitrate:Int 144 + - if(options.bitrate != -1) 145 + - { 146 + - audioBitrate= options.bitrate/1000 147 + - } 148 + - else 149 + - { 150 + - audioBitrate=AudioHelper.getDestinationBitrateByQuality(actualFileUrl, quality!!) 151 + - Utils.addLog("dest bitrate: $audioBitrate") 152 + - } 153 + - 154 + - var androidLame = LameBuilder(); 155 + - androidLame.setOutBitrate(audioBitrate) 156 + - 157 + - // for channels 158 + - var audioChannels:Int 159 + - if(options.channels != -1){ 160 + - audioChannels= options.channels!! 161 + - } 162 + - else 163 + - { 164 + - audioChannels=waveReader!!.channels 165 + - } 166 + - androidLame.setOutChannels(audioChannels) 167 + - 168 + - // for sample rate 169 + - androidLame.setInSampleRate(waveReader!!.sampleRate) 170 + - var audioSampleRate:Int 171 + - if(options.samplerate != -1){ 172 + - audioSampleRate= options.samplerate!! 173 + - } 174 + - else 175 + - { 176 + - audioSampleRate=waveReader!!.sampleRate 177 + - } 178 + - androidLame.setOutSampleRate(audioSampleRate) 179 + - val androidLameBuild=androidLame.build() 180 + - 181 + - try { 182 + - outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER) 183 + - } catch (e: FileNotFoundException) { 184 + - e.printStackTrace() 185 + - } 186 + - 187 + - var bytesRead = 0 188 + - 189 + - val buffer_l = ShortArray(CHUNK_SIZE) 190 + - val buffer_r = ShortArray(CHUNK_SIZE) 191 + - val mp3Buf = ByteArray(CHUNK_SIZE) 192 + - 193 + - val channels = waveReader!!.channels 194 + - 195 + - addLog("started encoding") 196 + - while (true) { 197 + - try { 198 + - if (channels == 2) { 199 + - 200 + - bytesRead = waveReader!!.read(buffer_l, buffer_r, CHUNK_SIZE) 201 + - addLog("bytes read=$bytesRead") 202 + - 203 + - if (bytesRead > 0) { 204 + - 205 + - var bytesEncoded = 0 206 + - bytesEncoded = androidLameBuild.encode(buffer_l, buffer_r, bytesRead, mp3Buf) 207 + - addLog("bytes encoded=$bytesEncoded") 208 + - 209 + - if (bytesEncoded > 0) { 210 + - try { 211 + - addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes") 212 + - outputStream!!.write(mp3Buf, 0, bytesEncoded) 213 + - } catch (e: IOException) { 214 + - e.printStackTrace() 215 + - } 216 + - 217 + - } 218 + - 219 + - } else 220 + - break 221 + - } else { 222 + - 223 + - bytesRead = waveReader!!.read(buffer_l, CHUNK_SIZE) 224 + - addLog("bytes read=$bytesRead") 225 + - 226 + - if (bytesRead > 0) { 227 + - var bytesEncoded = 0 228 + - 229 + - bytesEncoded = androidLameBuild.encode(buffer_l, buffer_l, bytesRead, mp3Buf) 230 + - addLog("bytes encoded=$bytesEncoded") 231 + - 232 + - if (bytesEncoded > 0) { 233 + - try { 234 + - addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes") 235 + - outputStream!!.write(mp3Buf, 0, bytesEncoded) 236 + - } catch (e: IOException) { 237 + - e.printStackTrace() 238 + - } 239 + - 240 + - } 241 + - 242 + - } else 243 + - break 244 + - } 245 + - 246 + - 247 + - } catch (e: IOException) { 248 + - e.printStackTrace() 249 + - } 250 + - 251 + - } 252 + - 253 + - addLog("flushing final mp3buffer") 254 + - val outputMp3buf = androidLameBuild.flush(mp3Buf) 255 + - addLog("flushed $outputMp3buf bytes") 256 + - if (outputMp3buf > 0) { 257 + - try { 258 + - addLog("writing final mp3buffer to outputstream") 259 + - outputStream!!.write(mp3Buf, 0, outputMp3buf) 260 + - addLog("closing output stream") 261 + - outputStream!!.close() 262 + - completeCallback(output.absolutePath, true) 263 + - isCompletedCallbackTriggered=true 264 + - } catch (e: IOException) { 265 + - completeCallback(e.localizedMessage, false) 266 + - e.printStackTrace() 267 + - } 268 + - } 269 + - 270 + - } catch (e: IOException) { 271 + - completeCallback(e.localizedMessage, false) 272 + - } 273 + - if(!isCompletedCallbackTriggered) 274 + - { 275 + - completeCallback("something went wrong", false) 276 + - } 277 + - } 278 + - 279 + - 280 + - 281 + - } 282 + -} 283 + diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt 284 + deleted file mode 100644 285 + index c655182..0000000 286 + --- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt 287 + +++ /dev/null 288 + @@ -1,112 +0,0 @@ 289 + -package com.reactnativecompressor.Audio 290 + - 291 + -import android.annotation.SuppressLint 292 + -import android.media.MediaCodec 293 + -import android.media.MediaExtractor 294 + -import android.media.MediaFormat 295 + -import android.media.MediaMetadataRetriever 296 + -import android.media.MediaMuxer 297 + -import android.util.Log 298 + -import java.io.IOException 299 + -import java.nio.ByteBuffer 300 + - 301 + - 302 + -class AudioExtractor { 303 + - /** 304 + - * @param srcPath the path of source video file. 305 + - * @param dstPath the path of destination video file. 306 + - * @param startMs starting time in milliseconds for trimming. Set to 307 + - * negative if starting from beginning. 308 + - * @param endMs end time for trimming in milliseconds. Set to negative if 309 + - * no trimming at the end. 310 + - * @param useAudio true if keep the audio track from the source. 311 + - * @param useVideo true if keep the video track from the source. 312 + - * @throws IOException 313 + - */ 314 + - @SuppressLint("NewApi", "WrongConstant") 315 + - @Throws(IOException::class) 316 + - fun genVideoUsingMuxer(srcPath: String?, dstPath: String?, startMs: Int, endMs: Int, useAudio: Boolean, useVideo: Boolean) { 317 + - // Set up MediaExtractor to read from the source. 318 + - val extractor = MediaExtractor() 319 + - extractor.setDataSource(srcPath!!) 320 + - val trackCount = extractor.trackCount 321 + - // Set up MediaMuxer for the destination. 322 + - val muxer: MediaMuxer 323 + - muxer = MediaMuxer(dstPath!!, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) 324 + - // Set up the tracks and retrieve the max buffer size for selected 325 + - // tracks. 326 + - val indexMap = HashMap<Int, Int>(trackCount) 327 + - var bufferSize = -1 328 + - for (i in 0 until trackCount) { 329 + - val format = extractor.getTrackFormat(i) 330 + - val mime = format.getString(MediaFormat.KEY_MIME) 331 + - var selectCurrentTrack = false 332 + - if (mime!!.startsWith("audio/") && useAudio) { 333 + - selectCurrentTrack = true 334 + - } else if (mime.startsWith("video/") && useVideo) { 335 + - selectCurrentTrack = true 336 + - } 337 + - if (selectCurrentTrack) { 338 + - extractor.selectTrack(i) 339 + - val dstIndex = muxer.addTrack(format) 340 + - indexMap[i] = dstIndex 341 + - if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) { 342 + - val newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE) 343 + - bufferSize = if (newSize > bufferSize) newSize else bufferSize 344 + - } 345 + - } 346 + - } 347 + - if (bufferSize < 0) { 348 + - bufferSize = DEFAULT_BUFFER_SIZE 349 + - } 350 + - // Set up the orientation and starting time for extractor. 351 + - val retrieverSrc = MediaMetadataRetriever() 352 + - retrieverSrc.setDataSource(srcPath) 353 + - val degreesString = retrieverSrc.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION) 354 + - if (degreesString != null) { 355 + - val degrees = degreesString.toInt() 356 + - if (degrees >= 0) { 357 + - muxer.setOrientationHint(degrees) 358 + - } 359 + - } 360 + - if (startMs > 0) { 361 + - extractor.seekTo((startMs * 1000).toLong(), MediaExtractor.SEEK_TO_CLOSEST_SYNC) 362 + - } 363 + - // Copy the samples from MediaExtractor to MediaMuxer. We will loop 364 + - // for copying each sample and stop when we get to the end of the source 365 + - // file or exceed the end time of the trimming. 366 + - val offset = 0 367 + - var trackIndex = -1 368 + - val dstBuf = ByteBuffer.allocate(bufferSize) 369 + - val bufferInfo = MediaCodec.BufferInfo() 370 + - muxer.start() 371 + - while (true) { 372 + - bufferInfo.offset = offset 373 + - bufferInfo.size = extractor.readSampleData(dstBuf, offset) 374 + - if (bufferInfo.size < 0) { 375 + - Log.d(TAG, "Saw input EOS.") 376 + - bufferInfo.size = 0 377 + - break 378 + - } else { 379 + - bufferInfo.presentationTimeUs = extractor.sampleTime 380 + - if (endMs > 0 && bufferInfo.presentationTimeUs > endMs * 1000) { 381 + - Log.d(TAG, "The current sample is over the trim end time.") 382 + - break 383 + - } else { 384 + - bufferInfo.flags = extractor.sampleFlags 385 + - trackIndex = extractor.sampleTrackIndex 386 + - muxer.writeSampleData(indexMap[trackIndex]!!, dstBuf, bufferInfo) 387 + - extractor.advance() 388 + - } 389 + - } 390 + - } 391 + - muxer.stop() 392 + - muxer.release() 393 + - return 394 + - } 395 + - 396 + - companion object { 397 + - private const val DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024 398 + - private const val TAG = "AudioExtractorDecoder" 399 + - } 400 + -} 401 + diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt 402 + deleted file mode 100644 403 + index 42040b4..0000000 404 + --- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt 405 + +++ /dev/null 406 + @@ -1,72 +0,0 @@ 407 + -package com.reactnativecompressor.Audio 408 + - 409 + -import android.media.MediaExtractor 410 + -import android.media.MediaFormat 411 + -import com.facebook.react.bridge.ReadableMap 412 + -import com.reactnativecompressor.Utils.Utils 413 + -import java.io.File 414 + -import java.io.IOException 415 + - 416 + - 417 + -class AudioHelper { 418 + - 419 + - var quality: String? = "medium" 420 + - var bitrate: Int = -1 421 + - var samplerate: Int = -1 422 + - var channels: Int = -1 423 + - var progressDivider: Int? = 0 424 + - 425 + - companion object { 426 + - fun fromMap(map: ReadableMap): AudioHelper { 427 + - val options = AudioHelper() 428 + - val iterator = map.keySetIterator() 429 + - while (iterator.hasNextKey()) { 430 + - val key = iterator.nextKey() 431 + - when (key) { 432 + - "quality" -> options.quality = map.getString(key) 433 + - "bitrate" -> { 434 + - val bitrate = map.getInt(key) 435 + - options.bitrate = if (bitrate > 320000 || bitrate < 64000) 64000 else bitrate 436 + - } 437 + - "samplerate" -> options.samplerate = map.getInt(key) 438 + - "channels" -> options.channels = map.getInt(key) 439 + - } 440 + - } 441 + - return options 442 + - } 443 + - 444 + - 445 + - fun getAudioBitrate(path: String): Int { 446 + - val file = File(path) 447 + - val fileSize = file.length() * 8 // size in bits 448 + - 449 + - val mex = MediaExtractor() 450 + - try { 451 + - mex.setDataSource(path) 452 + - } catch (e: IOException) { 453 + - e.printStackTrace() 454 + - } 455 + - 456 + - val mf = mex.getTrackFormat(0) 457 + - val durationUs = mf.getLong(MediaFormat.KEY_DURATION) 458 + - val durationSec = durationUs / 1_000_000.0 // convert duration to seconds 459 + - 460 + - return (fileSize / durationSec).toInt()/1000 // bitrate in bits per second 461 + - } 462 + - fun getDestinationBitrateByQuality(path: String, quality: String): Int { 463 + - val originalBitrate = getAudioBitrate(path) 464 + - var destinationBitrate = originalBitrate 465 + - Utils.addLog("source bitrate: $originalBitrate") 466 + - 467 + - when (quality.lowercase()) { 468 + - "low" -> destinationBitrate = maxOf(64, (originalBitrate * 0.3).toInt()) 469 + - "medium" -> destinationBitrate = (originalBitrate * 0.5).toInt() 470 + - "high" -> destinationBitrate = minOf(320, (originalBitrate * 0.7).toInt()) 471 + - else -> Utils.addLog("Invalid quality level. Please enter 'low', 'medium', or 'high'.") 472 + - } 473 + - 474 + - return destinationBitrate 475 + - } 476 + - 477 + - } 478 + -} 479 + diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt 480 + index 446d4fb..f021909 100644 481 + --- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt 482 + +++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt 483 + @@ -11,7 +11,9 @@ class AudioMain(private val reactContext: ReactApplicationContext) { 484 + promise: Promise) { 485 + try { 486 + 487 + - AudioCompressor.CompressAudio(fileUrl,optionMap,reactContext,promise) 488 + + // Skip compression on Android to avoid libandroidlame dependency 489 + + // Return the original file URL without compression 490 + + promise.resolve(fileUrl) 491 + } catch (ex: Exception) { 492 + promise.reject(ex) 493 + } 494 + diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt 495 + index c14b727..1198908 100644 496 + --- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt 497 + +++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt 498 + @@ -7,7 +7,6 @@ import android.provider.OpenableColumns 499 + import android.util.Log 500 + import com.facebook.react.bridge.Promise 501 + import com.facebook.react.bridge.ReactApplicationContext 502 + -import com.reactnativecompressor.Audio.AudioCompressor 503 + import com.reactnativecompressor.Video.VideoCompressor.CompressionListener 504 + import com.reactnativecompressor.Video.VideoCompressor.VideoCompressorClass 505 + import java.io.FileNotFoundException 506 + @@ -152,10 +151,6 @@ object Utils { 507 + } 508 + } 509 + 510 + - fun addLog(log: String) { 511 + - Log.d(AudioCompressor.TAG, log) 512 + - } 513 + - 514 + val exifAttributes = arrayOf( 515 + "FNumber", 516 + "ApertureValue",
+5
patches/react-native-compressor+1.13.0.patch.md
··· 1 + # react-native-compressor 2 + 3 + Patch file taken from https://github.com/numandev1/react-native-compressor/pull/355#issuecomment-3180870738 4 + 5 + This patch removes the audio compression feature on Android from the library. This is because `libandroidlame.so`, the native dependency, does not support 16kb page sizes, and the Play Store has made this mandatory as of 1st Nov 2025.