Works
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/rememberLottieComposition.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/rememberLottieComposition.kt
index 766abc2..5a66cfd 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/rememberLottieComposition.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/rememberLottieComposition.kt
@@ -196,23 +196,7 @@
         is LottieCompositionSpec.ContentProvider -> {
             val fis = context.contentResolver.openInputStream(spec.uri)
             val actualCacheKey = if (cacheKey == DefaultCacheKey) spec.uri.toString() else cacheKey
-            when {
-                spec.uri.toString().endsWith("zip") ||
-                    spec.uri.toString().endsWith("lottie") -> LottieCompositionFactory.fromZipStream(
-                    ZipInputStream(fis),
-                    actualCacheKey,
-                )
-
-                spec.uri.toString().endsWith("tgs") -> LottieCompositionFactory.fromJsonInputStream(
-                    GZIPInputStream(fis),
-                    actualCacheKey,
-                )
-
-                else -> LottieCompositionFactory.fromJsonInputStream(
-                    fis,
-                    actualCacheKey,
-                )
-            }
+            return LottieCompositionFactory.fromInputStream(context, fis, actualCacheKey)
         }
     }
 }
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
index d90ab0a..be5ca05 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
@@ -225,7 +225,40 @@
       return new LottieResult<>(cachedComposition);
     }
     try {
-      BufferedSource source = Okio.buffer(source(context.getAssets().open(fileName)));
+      return fromInputStreamSync(context, context.getAssets().open(fileName), cacheKey);
+    } catch (IOException e) {
+      return new LottieResult<>(e);
+    }
+  }
+
+  /**
+   * Use this when you have an input stream but aren't sure if it is a json, zip, or gzip file.
+   * This will read the file headers to see if it starts with the gzip or zip magic bytes.
+   * @param context is optional and only needed if your zip file contains ttf or otf fonts. If yours doesn't, you may pass null.
+   *                Embedded fonts may be .ttf or .otf files, can be in subdirectories, but must have the same name as the
+   *                font family (fFamily) in your animation file.
+   */
+  public static LottieTask<LottieComposition> fromInputStream(@Nullable Context context, InputStream inputStream, @Nullable String cacheKey) {
+    // Prevent accidentally leaking an Activity.
+    final Context appContext = context == null ? null : context.getApplicationContext();
+    return cache(cacheKey, () -> fromInputStreamSync(appContext, inputStream, cacheKey), null);
+  }
+
+  /**
+   * Use this when you have an input stream but aren't sure if it is a json, zip, or gzip file.
+   * This will read the file headers to see if it starts with the gzip or zip magic bytes.
+   * @param context is optional and only needed if your zip file contains ttf or otf fonts. If yours doesn't, you may pass null.
+   *                Embedded fonts may be .ttf or .otf files, can be in subdirectories, but must have the same name as the
+   *                font family (fFamily) in your animation file.
+   */
+  @WorkerThread
+  public static LottieResult<LottieComposition> fromInputStreamSync(@Nullable Context context, InputStream inputStream, @Nullable String cacheKey) {
+    final LottieComposition cachedComposition = cacheKey == null ? null : LottieCompositionCache.getInstance().get(cacheKey);
+    if (cachedComposition != null) {
+      return new LottieResult<>(cachedComposition);
+    }
+    try {
+      BufferedSource source = Okio.buffer(source(inputStream));
       if (isZipCompressed(source)) {
         return fromZipStreamSync(context, new ZipInputStream(source.inputStream()), cacheKey);
       } else if (isGzipCompressed(source)) {
@@ -553,7 +586,8 @@
   }
 
   @WorkerThread
-  private static LottieResult<LottieComposition> fromZipStreamSyncInternal(@Nullable Context context, ZipInputStream inputStream, @Nullable String cacheKey) {
+  private static LottieResult<LottieComposition> fromZipStreamSyncInternal(@Nullable Context context, ZipInputStream inputStream,
+      @Nullable String cacheKey) {
     LottieComposition composition = null;
     Map<String, Bitmap> images = new HashMap<>();
     Map<String, Typeface> fonts = new HashMap<>();
@@ -583,7 +617,8 @@
           String fontFamily = fileName.split("\\.")[0];
 
           if (context == null) {
-            return new LottieResult<>(new IllegalStateException("Unable to extract font " + fontFamily + " please pass a non-null Context parameter"));
+            return new LottieResult<>(
+                new IllegalStateException("Unable to extract font " + fontFamily + " please pass a non-null Context parameter"));
           }
 
           File tempFile = new File(context.getCacheDir(), fileName);