diff --git a/TrailerService b/TrailerService
new file mode 160000
index 00000000..2cb2c6d1
--- /dev/null
+++ b/TrailerService
@@ -0,0 +1 @@
+Subproject commit 2cb2c6d1a3ca60416160bdb28be800fe249207fc
diff --git a/babel.config.js b/babel.config.js
index a5c5a10b..a31657b0 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -4,6 +4,7 @@ module.exports = function (api) {
presets: ['babel-preset-expo'],
plugins: [
'react-native-worklets/plugin',
+ 'react-native-boost/plugin',
],
env: {
production: {
diff --git a/enginefs b/enginefs
new file mode 160000
index 00000000..3a70b36f
--- /dev/null
+++ b/enginefs
@@ -0,0 +1 @@
+Subproject commit 3a70b36f873307cd83fb3178bb891f73cf73aa87
diff --git a/ios/Nuvio.xcodeproj/project.pbxproj b/ios/Nuvio.xcodeproj/project.pbxproj
index 4bf304a6..1d96622b 100644
--- a/ios/Nuvio.xcodeproj/project.pbxproj
+++ b/ios/Nuvio.xcodeproj/project.pbxproj
@@ -460,8 +460,8 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
- PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app;
- PRODUCT_NAME = "Nuvio";
+ PRODUCT_BUNDLE_IDENTIFIER = com.nuviohub.app;
+ PRODUCT_NAME = Nuvio;
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -492,8 +492,8 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
- PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app";
- PRODUCT_NAME = "Nuvio";
+ PRODUCT_BUNDLE_IDENTIFIER = com.nuviohub.app;
+ PRODUCT_NAME = Nuvio;
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme b/ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme
index d56adf85..60f9eb04 100644
--- a/ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme
+++ b/ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme
@@ -82,7 +82,7 @@
buildConfiguration = "Debug">
diff --git a/ios/Nuvio/Info.plist b/ios/Nuvio/Info.plist
index d701baa9..4ab9b8d0 100644
--- a/ios/Nuvio/Info.plist
+++ b/ios/Nuvio/Info.plist
@@ -1,101 +1,98 @@
-
- CADisableMinimumFrameDurationOnPhone
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- Nuvio
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- $(PRODUCT_BUNDLE_PACKAGE_TYPE)
- CFBundleShortVersionString
- 1.2.5
- CFBundleSignature
- ????
- CFBundleURLTypes
-
-
- CFBundleURLSchemes
-
- nuvio
- com.nuvio.app
-
-
-
- CFBundleURLSchemes
-
- exp+nuvio
-
-
-
- CFBundleVersion
- 20
- LSMinimumSystemVersion
- 12.0
- LSRequiresIPhoneOS
-
- LSSupportsOpeningDocumentsInPlace
-
- NSAppTransportSecurity
-
- NSAllowsArbitraryLoads
-
-
- NSBonjourServices
-
- _http._tcp
-
- NSLocalNetworkUsageDescription
- Allow $(PRODUCT_NAME) to access your local network
- NSMicrophoneUsageDescription
- This app does not require microphone access.
- RCTNewArchEnabled
-
- RCTRootViewBackgroundColor
- 4278322180
- UIBackgroundModes
-
- audio
-
- UIFileSharingEnabled
-
- UILaunchStoryboardName
- SplashScreen
- UIRequiredDeviceCapabilities
-
- arm64
-
- UIRequiresFullScreen
-
- UIStatusBarStyle
- UIStatusBarStyleDefault
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UISupportedInterfaceOrientations~ipad
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UIUserInterfaceStyle
- Dark
- UIViewControllerBasedStatusBarAppearance
-
-
-
\ No newline at end of file
+
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Nuvio
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.2.5
+ CFBundleSignature
+ ????
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ nuvio
+ com.nuvio.app
+
+
+
+ CFBundleURLSchemes
+
+ exp+nuvio
+
+
+
+ CFBundleVersion
+ 20
+ LSMinimumSystemVersion
+ 12.0
+ LSRequiresIPhoneOS
+
+ LSSupportsOpeningDocumentsInPlace
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ NSBonjourServices
+
+ _http._tcp
+
+ RCTNewArchEnabled
+
+ RCTRootViewBackgroundColor
+ 4278322180
+ UIBackgroundModes
+
+ audio
+ fetch
+
+ UIFileSharingEnabled
+
+ UILaunchStoryboardName
+ SplashScreen
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UIRequiresFullScreen
+
+ UIStatusBarStyle
+ UIStatusBarStyleDefault
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIUserInterfaceStyle
+ Dark
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/ios/Nuvio/Nuvio.entitlements b/ios/Nuvio/Nuvio.entitlements
index a0bc443f..0c67376e 100644
--- a/ios/Nuvio/Nuvio.entitlements
+++ b/ios/Nuvio/Nuvio.entitlements
@@ -1,10 +1,5 @@
-
- aps-environment
- development
- com.apple.developer.associated-domains
-
-
-
\ No newline at end of file
+
+
diff --git a/ios/Nuvio/NuvioRelease.entitlements b/ios/Nuvio/NuvioRelease.entitlements
index a0bc443f..0c67376e 100644
--- a/ios/Nuvio/NuvioRelease.entitlements
+++ b/ios/Nuvio/NuvioRelease.entitlements
@@ -1,10 +1,5 @@
-
- aps-environment
- development
- com.apple.developer.associated-domains
-
-
-
\ No newline at end of file
+
+
diff --git a/package-lock.json b/package-lock.json
index 0e9a36bf..79e673e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,7 @@
"@react-navigation/native-stack": "^7.3.10",
"@react-navigation/stack": "^7.2.10",
"@sentry/react-native": "~7.3.0",
- "@shopify/flash-list": "2.0.2",
+ "@shopify/flash-list": "^2.1.0",
"@supabase/supabase-js": "^2.54.0",
"@types/lodash": "^4.17.16",
"@types/react-native-video": "^5.0.20",
@@ -2813,6 +2813,19 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@legendapp/list": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/@legendapp/list/-/list-2.0.13.tgz",
+ "integrity": "sha512-OL9rvxRDDqiQ07+QhldcRqCX5+VihtXbbZaoey0TVWJqQN5XPh9b9Buefax3/HjNRzCaYTx1lCoeW5dz20j+cA==",
+ "license": "MIT",
+ "dependencies": {
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/@lottiefiles/dotlottie-react": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.6.5.tgz",
@@ -3589,13 +3602,10 @@
}
},
"node_modules/@shopify/flash-list": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-2.0.2.tgz",
- "integrity": "sha512-zhlrhA9eiuEzja4wxVvotgXHtqd3qsYbXkQ3rsBfOgbFA9BVeErpDE/yEwtlIviRGEqpuFj/oU5owD6ByaNX+w==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-2.1.0.tgz",
+ "integrity": "sha512-/EIQlptG456yM5o9qNmNsmaZEFEOGvG3WGyb6GUAxSLlcKUGlPUkPI2NLW5wQSDEY4xSRa5zocUI+9xwmsM4Kg==",
"license": "MIT",
- "dependencies": {
- "tslib": "2.8.1"
- },
"peerDependencies": {
"@babel/runtime": "*",
"react": "*",
@@ -12949,6 +12959,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
"license": "0BSD"
},
"node_modules/tunnel-agent": {
diff --git a/package.json b/package.json
index 7f3d4927..6c96b1e0 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@expo/metro-runtime": "~6.1.2",
"@expo/vector-icons": "^15.0.2",
"@gorhom/bottom-sheet": "^5.2.6",
+ "@legendapp/list": "^2.0.13",
"@lottiefiles/dotlottie-react": "^0.6.5",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-native-community/blur": "^4.4.1",
@@ -28,7 +29,7 @@
"@react-navigation/native-stack": "^7.3.10",
"@react-navigation/stack": "^7.2.10",
"@sentry/react-native": "~7.3.0",
- "@shopify/flash-list": "2.0.2",
+ "@shopify/flash-list": "^2.1.0",
"@supabase/supabase-js": "^2.54.0",
"@types/lodash": "^4.17.16",
"@types/react-native-video": "^5.0.20",
@@ -67,6 +68,7 @@
"posthog-react-native": "^4.4.0",
"react": "19.1.0",
"react-native": "0.81.4",
+ "react-native-boost": "^0.6.2",
"react-native-bottom-tabs": "^0.12.2",
"react-native-gesture-handler": "~2.28.0",
"react-native-get-random-values": "^1.11.0",
@@ -80,7 +82,7 @@
"react-native-svg": "15.12.1",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "^10.3.0",
- "react-native-video": "^6.12.0",
+ "react-native-video": "^6.17.0",
"react-native-web": "^0.21.0",
"react-native-wheel-color-picker": "^1.3.1",
"react-native-worklets": "^0.6.1",
diff --git a/patches/react-native-video+6.17.0.patch b/patches/react-native-video+6.17.0.patch
new file mode 100644
index 00000000..ca97b5a9
--- /dev/null
+++ b/patches/react-native-video+6.17.0.patch
@@ -0,0 +1,1467 @@
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/results.bin b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/results.bin
+new file mode 100644
+index 0000000..0d259dd
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/results.bin
+@@ -0,0 +1 @@
++o/classes
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/transformed/classes/classes_dex/classes.dex b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/transformed/classes/classes_dex/classes.dex
+new file mode 100644
+index 0000000..f27c56f
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/.transforms/cde462de23ae0e930ed29ed683a0d845/transformed/classes/classes_dex/classes.dex differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/generated/source/buildConfig/debug/com/brentvatne/react/BuildConfig.java b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/generated/source/buildConfig/debug/com/brentvatne/react/BuildConfig.java
+new file mode 100644
+index 0000000..b26a50e
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/generated/source/buildConfig/debug/com/brentvatne/react/BuildConfig.java
+@@ -0,0 +1,22 @@
++/**
++ * Automatically generated file. DO NOT MODIFY
++ */
++package com.brentvatne.react;
++
++public final class BuildConfig {
++ public static final boolean DEBUG = Boolean.parseBoolean("true");
++ public static final String LIBRARY_PACKAGE_NAME = "com.brentvatne.react";
++ public static final String BUILD_TYPE = "debug";
++ // Field from default config.
++ public static final boolean IS_NEW_ARCHITECTURE_ENABLED = true;
++ // Field from default config.
++ public static final boolean USE_EXOPLAYER_DASH = true;
++ // Field from default config.
++ public static final boolean USE_EXOPLAYER_HLS = true;
++ // Field from default config.
++ public static final boolean USE_EXOPLAYER_IMA = false;
++ // Field from default config.
++ public static final boolean USE_EXOPLAYER_RTSP = false;
++ // Field from default config.
++ public static final boolean USE_EXOPLAYER_SMOOTH_STREAMING = true;
++}
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml
+new file mode 100644
+index 0000000..728c5a9
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml
+@@ -0,0 +1,7 @@
++
++
++
++
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json
+new file mode 100644
+index 0000000..247891c
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json
+@@ -0,0 +1,18 @@
++{
++ "version": 3,
++ "artifactType": {
++ "type": "AAPT_FRIENDLY_MERGED_MANIFESTS",
++ "kind": "Directory"
++ },
++ "applicationId": "com.brentvatne.react",
++ "variantName": "debug",
++ "elements": [
++ {
++ "type": "SINGLE",
++ "filters": [],
++ "attributes": [],
++ "outputFile": "AndroidManifest.xml"
++ }
++ ],
++ "elementType": "File"
++}
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar
+new file mode 100644
+index 0000000..1f4ce80
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties
+new file mode 100644
+index 0000000..1211b1e
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties
+@@ -0,0 +1,6 @@
++aarFormatVersion=1.0
++aarMetadataVersion=1.0
++minCompileSdk=1
++minCompileSdkExtension=0
++minAndroidGradlePluginVersion=1.0.0
++coreLibraryDesugaringEnabled=false
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json
+new file mode 100644
+index 0000000..9e26dfe
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json
+@@ -0,0 +1 @@
++{}
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt
+new file mode 100644
+index 0000000..e69de29
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar
+new file mode 100644
+index 0000000..9ec2b04
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar
+new file mode 100644
+index 0000000..0889def
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt
+new file mode 100644
+index 0000000..b5a67e1
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt
+@@ -0,0 +1,44 @@
++int color player_overlay_color 0x0
++int color red 0x0
++int color silver_gray 0x0
++int color white 0x0
++int dimen controller_wrapper_padding_top 0x0
++int dimen full_screen_margin 0x0
++int dimen full_screen_size 0x0
++int dimen live_wrapper_margin_top 0x0
++int dimen position_duration_horizontal_padding 0x0
++int dimen position_duration_text_size 0x0
++int dimen position_duration_width 0x0
++int dimen seekBar_height 0x0
++int dimen seekBar_wrapper_margin_top 0x0
++int drawable circle 0x0
++int id exo_duration 0x0
++int id exo_ffwd 0x0
++int id exo_fullscreen 0x0
++int id exo_live_container 0x0
++int id exo_live_icon 0x0
++int id exo_live_label 0x0
++int id exo_next 0x0
++int id exo_pause 0x0
++int id exo_play 0x0
++int id exo_play_pause_container 0x0
++int id exo_position 0x0
++int id exo_prev 0x0
++int id exo_progress 0x0
++int id exo_rew 0x0
++int id exo_settings 0x0
++int layout exo_legacy_player_control_view 0x0
++int string error_drm_not_supported 0x0
++int string error_drm_unknown 0x0
++int string error_drm_unsupported_scheme 0x0
++int string error_instantiating_decoder 0x0
++int string error_no_decoder 0x0
++int string error_no_secure_decoder 0x0
++int string error_querying_decoders 0x0
++int string media_playback_notification_text 0x0
++int string media_playback_notification_title 0x0
++int string playback_speed 0x0
++int string select_playback_speed 0x0
++int string settings 0x0
++int string unrecognized_media_format 0x0
++int style ExoMediaButton_FullScreen 0x0
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/drawable_circle.xml.flat b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/drawable_circle.xml.flat
+new file mode 100644
+index 0000000..e62758d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/drawable_circle.xml.flat differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/layout_exo_legacy_player_control_view.xml.flat b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/layout_exo_legacy_player_control_view.xml.flat
+new file mode 100644
+index 0000000..bb5b5f9
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/layout_exo_legacy_player_control_view.xml.flat differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug-mergeJavaRes/merge-state b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug-mergeJavaRes/merge-state
+new file mode 100644
+index 0000000..441a1d2
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug-mergeJavaRes/merge-state differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
+new file mode 100644
+index 0000000..842471c
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
+@@ -0,0 +1,3 @@
++#Thu Oct 16 20:19:39 IST 2025
++com.brentvatne.react.react-native-video-main-6\:/drawable/circle.xml=/Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/drawable/circle.xml
++com.brentvatne.react.react-native-video-main-6\:/layout/exo_legacy_player_control_view.xml=/Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/layout/exo_legacy_player_control_view.xml
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml
+new file mode 100644
+index 0000000..e8dd9e4
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merged.dir/values/values.xml
+@@ -0,0 +1,33 @@
++
++
++ #00000000
++ #FF0000
++ #FFBEBEBE
++ #FFFFFF
++ 4dp
++ 4dp
++ 30dp
++ 12dp
++ 4dp
++ 14sp
++ 50dp
++ 26dp
++ 4dp
++ Protected content not supported on API levels below 18
++ An unknown DRM error occurred
++ This device does not support the required DRM scheme
++ Unable to instantiate decoder %1$s
++ This device does not provide a decoder for %1$s
++ This device does not provide a secure decoder for %1$s
++ Unable to query device decoders
++ Preparing playback
++ Media playback
++ Playback Speed
++ Select Playback Speed
++ Settings
++ Unrecognized media format
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merger.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merger.xml
+new file mode 100644
+index 0000000..55ffc6b
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/debug/packageDebugResources/merger.xml
+@@ -0,0 +1,5 @@
++
++#FFBEBEBE#00000000#FFFFFF#FF00004dp4dp12dp4dp4dp50dp26dp30dp14spThis device does not provide a decoder for %1$sThis device does not provide a secure decoder for %1$sUnable to query device decodersUnable to instantiate decoder %1$sProtected content not supported on API levels below 18Unrecognized media formatThis device does not support the required DRM schemeAn unknown DRM error occurredSettingsPlayback SpeedSelect Playback SpeedMedia playbackPreparing playback
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugAssets/merger.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugAssets/merger.xml
+new file mode 100644
+index 0000000..8769311
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugAssets/merger.xml
+@@ -0,0 +1,2 @@
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugJniLibFolders/merger.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugJniLibFolders/merger.xml
+new file mode 100644
+index 0000000..af687a7
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugJniLibFolders/merger.xml
+@@ -0,0 +1,2 @@
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugShaders/merger.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugShaders/merger.xml
+new file mode 100644
+index 0000000..65138a3
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/incremental/mergeDebugShaders/merger.xml
+@@ -0,0 +1,2 @@
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/react-native-video_debug.kotlin_module b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/react-native-video_debug.kotlin_module
+new file mode 100644
+index 0000000..1698483
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/react-native-video_debug.kotlin_module differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader$Builder.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader$Builder.class
+new file mode 100644
+index 0000000..b019110
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader$Builder.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader.class
+new file mode 100644
+index 0000000..5e16e53
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/ima/ImaAdsLoader.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource$Factory.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource$Factory.class
+new file mode 100644
+index 0000000..b08faeb
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource$Factory.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource.class
+new file mode 100644
+index 0000000..2f92e20
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/androidx/media3/exoplayer/rtsp/RtspMediaSource.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$1.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$1.class
+new file mode 100644
+index 0000000..a1368f5
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$1.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$2.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$2.class
+new file mode 100644
+index 0000000..ec7b745
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$2.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$3.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$3.class
+new file mode 100644
+index 0000000..598654a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$3.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$4.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$4.class
+new file mode 100644
+index 0000000..803aefe
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$4.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$OnAudioFocusChangedListener.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$OnAudioFocusChangedListener.class
+new file mode 100644
+index 0000000..6ec4ad1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$OnAudioFocusChangedListener.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$RNVLoadControl.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$RNVLoadControl.class
+new file mode 100644
+index 0000000..22d8796
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView$RNVLoadControl.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView.class
+new file mode 100644
+index 0000000..53eee7f
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/exoplayer/ReactExoplayerView.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/react/BuildConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/react/BuildConfig.class
+new file mode 100644
+index 0000000..4c5c87e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/brentvatne/react/BuildConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdError.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdError.class
+new file mode 100644
+index 0000000..0a9b7a7
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdError.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent$AdErrorListener.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent$AdErrorListener.class
+new file mode 100644
+index 0000000..1380a05
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent$AdErrorListener.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent.class
+new file mode 100644
+index 0000000..07ab3fa
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdErrorEvent.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent$AdEventListener.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent$AdEventListener.class
+new file mode 100644
+index 0000000..dbe9984
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent$AdEventListener.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent.class
+new file mode 100644
+index 0000000..88ae34c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/AdEvent.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkFactory.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkFactory.class
+new file mode 100644
+index 0000000..a3184b3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkFactory.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkSettings.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkSettings.class
+new file mode 100644
+index 0000000..264cd83
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ConcreteImaSdkSettings.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkFactory.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkFactory.class
+new file mode 100644
+index 0000000..46cea81
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkFactory.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkSettings.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkSettings.class
+new file mode 100644
+index 0000000..a4cef0d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/google/ads/interactivemedia/v3/api/ImaSdkSettings.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt
+new file mode 100644
+index 0000000..987e479
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt
+@@ -0,0 +1,46 @@
++R_DEF: Internal format may change without notice
++local
++color player_overlay_color
++color red
++color silver_gray
++color white
++dimen controller_wrapper_padding_top
++dimen full_screen_margin
++dimen full_screen_size
++dimen live_wrapper_margin_top
++dimen position_duration_horizontal_padding
++dimen position_duration_text_size
++dimen position_duration_width
++dimen seekBar_height
++dimen seekBar_wrapper_margin_top
++drawable circle
++id exo_duration
++id exo_ffwd
++id exo_fullscreen
++id exo_live_container
++id exo_live_icon
++id exo_live_label
++id exo_next
++id exo_pause
++id exo_play
++id exo_play_pause_container
++id exo_position
++id exo_prev
++id exo_progress
++id exo_rew
++id exo_settings
++layout exo_legacy_player_control_view
++string error_drm_not_supported
++string error_drm_unknown
++string error_drm_unsupported_scheme
++string error_instantiating_decoder
++string error_no_decoder
++string error_no_secure_decoder
++string error_querying_decoders
++string media_playback_notification_text
++string media_playback_notification_title
++string playback_speed
++string select_playback_speed
++string settings
++string unrecognized_media_format
++style ExoMediaButton.FullScreen
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt
+new file mode 100644
+index 0000000..2300097
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt
+@@ -0,0 +1,7 @@
++1
++2
++4
++5
++6
++7
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-react-native-video.jar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-react-native-video.jar
+new file mode 100644
+index 0000000..87d384d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-react-native-video.jar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml
+new file mode 100644
+index 0000000..728c5a9
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml
+@@ -0,0 +1,7 @@
++
++
++
++
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json
+new file mode 100644
+index 0000000..0637a08
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json
+@@ -0,0 +1 @@
++[]
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt
+new file mode 100644
+index 0000000..08f4ebe
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt
+@@ -0,0 +1 @@
++0 Warning/Error
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/drawable/circle.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/drawable/circle.xml
+new file mode 100644
+index 0000000..9f06d7c
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/drawable/circle.xml
+@@ -0,0 +1,6 @@
++
++
++
++
++
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/layout/exo_legacy_player_control_view.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/layout/exo_legacy_player_control_view.xml
+new file mode 100644
+index 0000000..e0babc4
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/layout/exo_legacy_player_control_view.xml
+@@ -0,0 +1,120 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/values/values.xml b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/values/values.xml
+new file mode 100644
+index 0000000..e8dd9e4
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/packaged_res/debug/packageDebugResources/values/values.xml
+@@ -0,0 +1,33 @@
++
++
++ #00000000
++ #FF0000
++ #FFBEBEBE
++ #FFFFFF
++ 4dp
++ 4dp
++ 30dp
++ 12dp
++ 4dp
++ 14sp
++ 50dp
++ 26dp
++ 4dp
++ Protected content not supported on API levels below 18
++ An unknown DRM error occurred
++ This device does not support the required DRM scheme
++ Unable to instantiate decoder %1$s
++ This device does not provide a decoder for %1$s
++ This device does not provide a secure decoder for %1$s
++ Unable to query device decoders
++ Preparing playback
++ Media playback
++ Playback Speed
++ Select Playback Speed
++ Settings
++ Unrecognized media format
++
++
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar
+new file mode 100644
+index 0000000..e65b062
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt
+new file mode 100644
+index 0000000..1cb95ed
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt
+@@ -0,0 +1,45 @@
++com.brentvatne.react
++color player_overlay_color
++color red
++color silver_gray
++color white
++dimen controller_wrapper_padding_top
++dimen full_screen_margin
++dimen full_screen_size
++dimen live_wrapper_margin_top
++dimen position_duration_horizontal_padding
++dimen position_duration_text_size
++dimen position_duration_width
++dimen seekBar_height
++dimen seekBar_wrapper_margin_top
++drawable circle
++id exo_duration
++id exo_ffwd
++id exo_fullscreen
++id exo_live_container
++id exo_live_icon
++id exo_live_label
++id exo_next
++id exo_pause
++id exo_play
++id exo_play_pause_container
++id exo_position
++id exo_prev
++id exo_progress
++id exo_rew
++id exo_settings
++layout exo_legacy_player_control_view
++string error_drm_not_supported
++string error_drm_unknown
++string error_drm_unsupported_scheme
++string error_instantiating_decoder
++string error_no_decoder
++string error_no_secure_decoder
++string error_querying_decoders
++string media_playback_notification_text
++string media_playback_notification_title
++string playback_speed
++string select_playback_speed
++string settings
++string unrecognized_media_format
++style ExoMediaButton_FullScreen
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab
+new file mode 100644
+index 0000000..7df5bcf
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream
+new file mode 100644
+index 0000000..1a55594
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len
+new file mode 100644
+index 0000000..74ddf64
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len
+new file mode 100644
+index 0000000..41d6c24
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at
+new file mode 100644
+index 0000000..d0eda54
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i
+new file mode 100644
+index 0000000..8a80b7d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab
+new file mode 100644
+index 0000000..532458c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream
+new file mode 100644
+index 0000000..1d1d548
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len
+new file mode 100644
+index 0000000..3247724
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len
+new file mode 100644
+index 0000000..bba171d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at
+new file mode 100644
+index 0000000..5d6b64a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i
+new file mode 100644
+index 0000000..045022c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab
+new file mode 100644
+index 0000000..8178530
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream
+new file mode 100644
+index 0000000..1d1d548
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len
+new file mode 100644
+index 0000000..3247724
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len
+new file mode 100644
+index 0000000..bba171d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at
+new file mode 100644
+index 0000000..6a45a65
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i
+new file mode 100644
+index 0000000..045022c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab
+new file mode 100644
+index 0000000..496bda2
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream
+new file mode 100644
+index 0000000..a49789c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len
+new file mode 100644
+index 0000000..a3d0573
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len
+new file mode 100644
+index 0000000..93a595b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at
+new file mode 100644
+index 0000000..9d91003
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i
+new file mode 100644
+index 0000000..1598ef3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab
+new file mode 100644
+index 0000000..c3975e3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream
+new file mode 100644
+index 0000000..9d05b9a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len
+new file mode 100644
+index 0000000..d3e09af
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len
+new file mode 100644
+index 0000000..b7d7395
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at
+new file mode 100644
+index 0000000..e3911a1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i
+new file mode 100644
+index 0000000..af27d9c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab
+new file mode 100644
+index 0000000..bdf584a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream
+new file mode 100644
+index 0000000..a9e6823
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len
+new file mode 100644
+index 0000000..de8bf97
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len
+new file mode 100644
+index 0000000..2a17e6e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at
+new file mode 100644
+index 0000000..46d6744
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i
+new file mode 100644
+index 0000000..2073982
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab
+new file mode 100644
+index 0000000..c626f49
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream
+new file mode 100644
+index 0000000..7214377
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len
+new file mode 100644
+index 0000000..86b154b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len
+new file mode 100644
+index 0000000..882f24f
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values
+new file mode 100644
+index 0000000..2ff3eb7
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at
+new file mode 100644
+index 0000000..af661f7
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s
+new file mode 100644
+index 0000000..b6551b9
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s
+@@ -0,0 +1 @@
++ÏÒ
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i
+new file mode 100644
+index 0000000..0cbafa1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab
+new file mode 100644
+index 0000000..85d9216
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream
+new file mode 100644
+index 0000000..1a55594
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len
+new file mode 100644
+index 0000000..74ddf64
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len
+new file mode 100644
+index 0000000..41d6c24
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at
+new file mode 100644
+index 0000000..dfc60fb
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i
+new file mode 100644
+index 0000000..8a80b7d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab
+new file mode 100644
+index 0000000..95c2c01
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream
+new file mode 100644
+index 0000000..90b21c4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len
+new file mode 100644
+index 0000000..4cb813c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len
+new file mode 100644
+index 0000000..385642d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at
+new file mode 100644
+index 0000000..195d865
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i
+new file mode 100644
+index 0000000..5e4a0c0
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab
+new file mode 100644
+index 0000000..d98dace
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream
+new file mode 100644
+index 0000000..ae4ac93
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len
+new file mode 100644
+index 0000000..6dc1435
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len
+new file mode 100644
+index 0000000..42df8b9
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at
+new file mode 100644
+index 0000000..bc345c6
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i
+new file mode 100644
+index 0000000..f0c9463
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab
+new file mode 100644
+index 0000000..672070d
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab
+@@ -0,0 +1,2 @@
++44
++0
+\ No newline at end of file
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab
+new file mode 100644
+index 0000000..1878d5a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream
+new file mode 100644
+index 0000000..1a55594
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len
+new file mode 100644
+index 0000000..74ddf64
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len
+new file mode 100644
+index 0000000..41d6c24
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at
+new file mode 100644
+index 0000000..d3fcc7e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i
+new file mode 100644
+index 0000000..8a80b7d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab
+new file mode 100644
+index 0000000..04aeda4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream
+new file mode 100644
+index 0000000..132a271
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len
+new file mode 100644
+index 0000000..79ad34c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len
+new file mode 100644
+index 0000000..41d6c24
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at
+new file mode 100644
+index 0000000..c834290
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i
+new file mode 100644
+index 0000000..1601c02
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab
+new file mode 100644
+index 0000000..5fc703e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream
+new file mode 100644
+index 0000000..39f4cac
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len
+new file mode 100644
+index 0000000..e381b23
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len
+new file mode 100644
+index 0000000..35ed991
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at
+new file mode 100644
+index 0000000..a262c4a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i
+new file mode 100644
+index 0000000..1bfa622
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len
+new file mode 100644
+index 0000000..131e265
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/last-build.bin b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/last-build.bin
+new file mode 100644
+index 0000000..1fe138d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/cacheable/last-build.bin differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin
+new file mode 100644
+index 0000000..fb7ec91
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/aar/react-native-video-debug.aar b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/aar/react-native-video-debug.aar
+new file mode 100644
+index 0000000..a704fe4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/aar/react-native-video-debug.aar differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/logs/manifest-merger-debug-report.txt b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/logs/manifest-merger-debug-report.txt
+new file mode 100644
+index 0000000..a388215
+--- /dev/null
++++ b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/outputs/logs/manifest-merger-debug-report.txt
+@@ -0,0 +1,16 @@
++-- Merging decision tree log ---
++manifest
++ADDED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml:1:1-2:12
++INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml:1:1-2:12
++ package
++ INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml
++ xmlns:android
++ ADDED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml:1:11-69
++uses-sdk
++INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml reason: use-sdk injection requested
++INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml
++INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml
++ android:targetSdkVersion
++ INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml
++ android:minSdkVersion
++ INJECTED from /Users/nayifnoushad/Documents/Projects/NuvioStreaming/node_modules/react-native-video/android/src/main/AndroidManifestNew.xml
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin
+new file mode 100644
+index 0000000..b63c0e3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/META-INF/react-native-video_debug.kotlin_module b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/META-INF/react-native-video_debug.kotlin_module
+new file mode 100644
+index 0000000..1698483
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/META-INF/react-native-video_debug.kotlin_module differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps$Companion.class
+new file mode 100644
+index 0000000..2e5d42b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps.class
+new file mode 100644
+index 0000000..e2b54bd
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/AdsProps.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Companion.class
+new file mode 100644
+index 0000000..0fbaa90
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live$Companion.class
+new file mode 100644
+index 0000000..ce1128e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live.class
+new file mode 100644
+index 0000000..2054200
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig$Live.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig.class
+new file mode 100644
+index 0000000..7ef226b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$BufferingStrategyEnum.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$BufferingStrategyEnum.class
+new file mode 100644
+index 0000000..162566c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$BufferingStrategyEnum.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$Companion.class
+new file mode 100644
+index 0000000..7477be8
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy.class
+new file mode 100644
+index 0000000..3516405
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/BufferingStrategy.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion$WhenMappings.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion$WhenMappings.class
+new file mode 100644
+index 0000000..5145552
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion$WhenMappings.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion.class
+new file mode 100644
+index 0000000..e813d1a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps.class
+new file mode 100644
+index 0000000..e6c0538
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/CMCDProps.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig$Companion.class
+new file mode 100644
+index 0000000..b2e5cfc
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig.class
+new file mode 100644
+index 0000000..a672b48
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ControlsConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps$Companion.class
+new file mode 100644
+index 0000000..949a5b9
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps.class
+new file mode 100644
+index 0000000..8e26a44
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/DRMProps.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode$Mode.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode$Mode.class
+new file mode 100644
+index 0000000..8c2948d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode$Mode.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode.class
+new file mode 100644
+index 0000000..ab7c203
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ResizeMode.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack$Companion.class
+new file mode 100644
+index 0000000..3262de8
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack.class
+new file mode 100644
+index 0000000..a6b7907
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrack.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList$Companion.class
+new file mode 100644
+index 0000000..a41fe7d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList.class
+new file mode 100644
+index 0000000..ec0f170
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SideLoadedTextTrackList.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Companion.class
+new file mode 100644
+index 0000000..20c7316
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata$Companion.class
+new file mode 100644
+index 0000000..3a83d08
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata.class
+new file mode 100644
+index 0000000..381c5ea
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source$Metadata.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source.class
+new file mode 100644
+index 0000000..763511c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Source.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle$Companion.class
+new file mode 100644
+index 0000000..1ef82f1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle.class
+new file mode 100644
+index 0000000..4ebb38c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/SubtitleStyle.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/TimedMetadata.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/TimedMetadata.class
+new file mode 100644
+index 0000000..81dc3f7
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/TimedMetadata.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Track.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Track.class
+new file mode 100644
+index 0000000..bf9687d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/Track.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/VideoTrack.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/VideoTrack.class
+new file mode 100644
+index 0000000..a011166
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/VideoTrack.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType$ViewType.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType$ViewType.class
+new file mode 100644
+index 0000000..2dfe0a5
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType$ViewType.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType.class
+new file mode 100644
+index 0000000..24c319c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/api/ViewType.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes$Companion.class
+new file mode 100644
+index 0000000..7c1c2f6
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes.class
+new file mode 100644
+index 0000000..68c48f1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/EventTypes.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$EventBuilder.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$EventBuilder.class
+new file mode 100644
+index 0000000..0dceebe
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$EventBuilder.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$VideoCustomEvent.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$VideoCustomEvent.class
+new file mode 100644
+index 0000000..6116962
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter$VideoCustomEvent.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter.class
+new file mode 100644
+index 0000000..1f63a29
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/react/VideoEventEmitter.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/DebugLog.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/DebugLog.class
+new file mode 100644
+index 0000000..35fd981
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/DebugLog.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/ReactBridgeUtils.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/ReactBridgeUtils.class
+new file mode 100644
+index 0000000..5b3a99d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/common/toolbox/ReactBridgeUtils.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout$Companion.class
+new file mode 100644
+index 0000000..e1e118c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout.class
+new file mode 100644
+index 0000000..8955650
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AspectRatioFrameLayout.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput$Companion.class
+new file mode 100644
+index 0000000..fdbd8c4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput.class
+new file mode 100644
+index 0000000..49bd1a1
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/AudioOutput.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig$createCmcdConfiguration$1.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig$createCmcdConfiguration$1.class
+new file mode 100644
+index 0000000..1b9ff2b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig$createCmcdConfiguration$1.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig.class
+new file mode 100644
+index 0000000..24ff469
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/CMCDConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ConfigurationUtils.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ConfigurationUtils.class
+new file mode 100644
+index 0000000..8623659
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ConfigurationUtils.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManager.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManager.class
+new file mode 100644
+index 0000000..c054558
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManager.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManagerSpec.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManagerSpec.class
+new file mode 100644
+index 0000000..3ba0b21
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DRMManagerSpec.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DataSourceUtil.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DataSourceUtil.class
+new file mode 100644
+index 0000000..435095f
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DataSourceUtil.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.class
+new file mode 100644
+index 0000000..7d79368
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$Companion.class
+new file mode 100644
+index 0000000..345dd50
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$playerListener$1.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$playerListener$1.class
+new file mode 100644
+index 0000000..4dcc80e
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView$playerListener$1.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView.class
+new file mode 100644
+index 0000000..df0ace7
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ExoPlayerView.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater$Companion.class
+new file mode 100644
+index 0000000..8bcae8d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater.class
+new file mode 100644
+index 0000000..550135d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView$KeepScreenOnUpdater.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView.class
+new file mode 100644
+index 0000000..257de83
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/FullScreenPlayerView.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtil.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtil.class
+new file mode 100644
+index 0000000..9e8c1b9
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtil.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtilKt.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtilKt.class
+new file mode 100644
+index 0000000..2c42f4a
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PictureInPictureUtilKt.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PlaybackServiceBinder.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PlaybackServiceBinder.class
+new file mode 100644
+index 0000000..5ae25b4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/PlaybackServiceBinder.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin$DefaultImpls.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin$DefaultImpls.class
+new file mode 100644
+index 0000000..af3decf
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin$DefaultImpls.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin.class
+new file mode 100644
+index 0000000..9bc6115
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVExoplayerPlugin.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVSimpleCache.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVSimpleCache.class
+new file mode 100644
+index 0000000..659e439
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/RNVSimpleCache.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerConfig.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerConfig.class
+new file mode 100644
+index 0000000..2456c95
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerConfig.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.class
+new file mode 100644
+index 0000000..38ce458
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager$Companion.class
+new file mode 100644
+index 0000000..bc906a9
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager.class
+new file mode 100644
+index 0000000..07bd865
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/ReactExoplayerViewManager.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackCallback.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackCallback.class
+new file mode 100644
+index 0000000..5e67aa0
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackCallback.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$COMMAND.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$COMMAND.class
+new file mode 100644
+index 0000000..6ba65f2
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$COMMAND.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$WhenMappings.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$WhenMappings.class
+new file mode 100644
+index 0000000..647f782
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion$WhenMappings.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion.class
+new file mode 100644
+index 0000000..0f20e85
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService.class
+new file mode 100644
+index 0000000..8a576c2
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/exoplayer/VideoPlaybackService.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/RNVPlugin.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/RNVPlugin.class
+new file mode 100644
+index 0000000..8a59f22
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/RNVPlugin.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager$Companion.class
+new file mode 100644
+index 0000000..32d6d1f
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager.class
+new file mode 100644
+index 0000000..2679ae0
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactNativeVideoManager.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactVideoPackage.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactVideoPackage.class
+new file mode 100644
+index 0000000..2af2d2c
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/ReactVideoPackage.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule$Companion.class
+new file mode 100644
+index 0000000..d8a4aa3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule.class
+new file mode 100644
+index 0000000..8348d9d
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoDecoderInfoModule.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule$Companion.class
+new file mode 100644
+index 0000000..435293b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule.class
+new file mode 100644
+index 0000000..c28e02b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/react/VideoManagerModule.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/AudioBecomingNoisyReceiver.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/AudioBecomingNoisyReceiver.class
+new file mode 100644
+index 0000000..990ca48
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/AudioBecomingNoisyReceiver.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion$NO_OP$1.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion$NO_OP$1.class
+new file mode 100644
+index 0000000..07a503b
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion$NO_OP$1.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion.class
+new file mode 100644
+index 0000000..efa3ee3
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener.class
+new file mode 100644
+index 0000000..75d1cd4
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/BecomingNoisyListener.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver$Companion.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver$Companion.class
+new file mode 100644
+index 0000000..535aad5
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver$Companion.class differ
+diff --git a/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver.class b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver.class
+new file mode 100644
+index 0000000..0143f64
+Binary files /dev/null and b/node_modules/react-native-video/android/buildOutput_a15d4dee7fc4eda61b91308cbb6a2e72/tmp/kotlin-classes/debug/com/brentvatne/receiver/PictureInPictureReceiver.class differ
+diff --git a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
+index f175dec..87e436a 100644
+--- a/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
++++ b/node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
+@@ -726,7 +726,7 @@ public class ReactExoplayerView extends FrameLayout implements
+
+ DefaultRenderersFactory renderersFactory =
+ new DefaultRenderersFactory(getContext())
+- .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF)
++ .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
+ .setEnableDecoderFallback(true)
+ .forceEnableMediaCodecAsynchronousQueueing();
+
diff --git a/src/components/home/CatalogSection.tsx b/src/components/home/CatalogSection.tsx
index 77fd6af2..7639a9f0 100644
--- a/src/components/home/CatalogSection.tsx
+++ b/src/components/home/CatalogSection.tsx
@@ -1,6 +1,6 @@
import React, { useCallback, useMemo, useRef } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform, Dimensions } from 'react-native';
-import { FlashList } from '@shopify/flash-list';
+import { LegendList } from '@legendapp/list';
import { NavigationProp, useNavigation } from '@react-navigation/native';
import { MaterialIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
@@ -98,7 +98,7 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
- {
ItemSeparatorComponent={ItemSeparator}
onEndReachedThreshold={0.7}
onEndReached={() => {}}
- scrollEventThrottle={64}
- removeClippedSubviews={true}
+ recycleItems={true}
+ maintainVisibleContentPosition
/>
);
diff --git a/src/components/home/HeroCarousel.tsx b/src/components/home/HeroCarousel.tsx
index fb7e20c5..58b13981 100644
--- a/src/components/home/HeroCarousel.tsx
+++ b/src/components/home/HeroCarousel.tsx
@@ -1,6 +1,6 @@
-import React, { useMemo, useState, useEffect, useCallback, memo } from 'react';
-import { View, Text, StyleSheet, Dimensions, TouchableOpacity, ViewStyle, TextStyle, ImageStyle, FlatList, StyleProp, Platform, Image } from 'react-native';
-import Animated, { FadeIn, FadeOut, Easing, useSharedValue, withTiming, useAnimatedStyle, useAnimatedScrollHandler, useAnimatedReaction, runOnJS } from 'react-native-reanimated';
+import React, { useMemo, useState, useEffect, useCallback, memo, useRef } from 'react';
+import { View, Text, StyleSheet, Dimensions, TouchableOpacity, ViewStyle, TextStyle, ImageStyle, ScrollView, StyleProp, Platform, Image } from 'react-native';
+import Animated, { FadeIn, FadeOut, Easing, useSharedValue, withTiming, useAnimatedStyle, useAnimatedScrollHandler, useAnimatedReaction, runOnJS, SharedValue } from 'react-native-reanimated';
import { LinearGradient } from 'expo-linear-gradient';
import { BlurView } from 'expo-blur';
import FastImage from '@d11/react-native-fast-image';
@@ -47,6 +47,7 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
const data = useMemo(() => (items && items.length ? items.slice(0, 10) : []), [items]);
const [activeIndex, setActiveIndex] = useState(0);
const [failedLogoIds, setFailedLogoIds] = useState>(new Set());
+ const scrollViewRef = useRef(null);
// Note: do not early-return before hooks. Loading UI is returned later.
@@ -55,10 +56,50 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
// Optimized: update background as soon as scroll starts, without waiting for momentum end
const scrollX = useSharedValue(0);
const interval = CARD_WIDTH + 16;
+
+ // Comprehensive reset when component mounts/remounts to prevent glitching
+ useEffect(() => {
+ scrollX.value = 0;
+ setActiveIndex(0);
+
+ // Scroll to position 0 after a brief delay to ensure ScrollView is ready
+ const timer = setTimeout(() => {
+ scrollViewRef.current?.scrollTo({ x: 0, y: 0, animated: false });
+ }, 50);
+
+ return () => clearTimeout(timer);
+ }, []);
+
+ // Reset scroll when data becomes available
+ useEffect(() => {
+ if (data.length > 0) {
+ scrollX.value = 0;
+ setActiveIndex(0);
+
+ const timer = setTimeout(() => {
+ scrollViewRef.current?.scrollTo({ x: 0, y: 0, animated: false });
+ }, 100);
+
+ return () => clearTimeout(timer);
+ }
+ }, [data.length]);
+
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollX.value = event.contentOffset.x;
},
+ onBeginDrag: () => {
+ // Smooth scroll start - could add haptic feedback here
+ },
+ onEndDrag: () => {
+ // Smooth scroll end
+ },
+ onMomentumBegin: () => {
+ // Momentum scroll start
+ },
+ onMomentumEnd: () => {
+ // Momentum scroll end
+ },
});
// Derive the index reactively and only set state when it changes
@@ -78,17 +119,6 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
const contentPadding = useMemo(() => ({ paddingHorizontal: (width - CARD_WIDTH) / 2 }), []);
- const keyExtractor = useCallback((item: StreamingContent) => item.id, []);
-
- const getItemLayout = useCallback(
- (_: unknown, index: number) => {
- const length = CARD_WIDTH + 16;
- const offset = length * index;
- return { length, offset, index };
- },
- []
- );
-
const handleNavigateToMetadata = useCallback((id: string, type: any) => {
navigation.navigate('Metadata', { id, type });
}, [navigation]);
@@ -97,20 +127,31 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
navigation.navigate('Streams', { id, type });
}, [navigation]);
+ // Container animation based on scroll - must be before early returns
+ const containerAnimatedStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const progress = Math.abs(translateX) / (data.length * (CARD_WIDTH + 16));
+
+ // Very subtle scale animation for the entire container
+ const scale = 1 - progress * 0.01;
+ const clampedScale = Math.max(0.99, Math.min(1, scale));
+
+ return {
+ transform: [{ scale: clampedScale }],
+ };
+ });
+
if (loading) {
return (
}>
- String(i)}
+ (
-
+ >
+ {[1, 2, 3].map((_, index) => (
+
= ({ items, loading = false }) =
- )}
- />
+ ))}
+
);
@@ -222,7 +263,7 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
return (
-
+
{settings.enableHomeHeroBackground && data.length > 0 && (
{data[activeIndex + 1] && (
@@ -264,37 +305,35 @@ const HeroCarousel: React.FC = ({ items, loading = false }) =
pointerEvents="none"
/>
)}
- (
-
- setFailedLogoIds((prev) => new Set(prev).add(item.id))}
- onPressInfo={() => handleNavigateToMetadata(item.id, item.type)}
- onPressPlay={() => handleNavigateToStreams(item.id, item.type)}
- />
-
- )}
- />
-
+ pagingEnabled={false}
+ bounces={false}
+ overScrollMode="never"
+ >
+ {data.map((item, index) => (
+ setFailedLogoIds((prev) => new Set(prev).add(item.id))}
+ onPressInfo={() => handleNavigateToMetadata(item.id, item.type)}
+ onPressPlay={() => handleNavigateToStreams(item.id, item.type)}
+ scrollX={scrollX}
+ index={index}
+ />
+ ))}
+
+
);
};
@@ -306,61 +345,208 @@ interface CarouselCardProps {
onLogoError: () => void;
onPressPlay: () => void;
onPressInfo: () => void;
+ scrollX: SharedValue;
+ index: number;
}
-const CarouselCard: React.FC = memo(({ item, colors, logoFailed, onLogoError, onPressPlay, onPressInfo }) => {
+const CarouselCard: React.FC = memo(({ item, colors, logoFailed, onLogoError, onPressPlay, onPressInfo, scrollX, index }) => {
+ const [bannerLoaded, setBannerLoaded] = useState(false);
+ const [logoLoaded, setLogoLoaded] = useState(false);
+
+ const bannerOpacity = useSharedValue(0);
+ const logoOpacity = useSharedValue(0);
+ const genresOpacity = useSharedValue(0);
+ const actionsOpacity = useSharedValue(0);
+
+ // Reset animations when component mounts/remounts to prevent glitching
+ useEffect(() => {
+ bannerOpacity.value = 0;
+ logoOpacity.value = 0;
+ genresOpacity.value = 0;
+ actionsOpacity.value = 0;
+ // Force re-render states to ensure clean state
+ setBannerLoaded(false);
+ setLogoLoaded(false);
+ }, [item.id]);
+
+ const inputRange = [
+ (index - 1) * (CARD_WIDTH + 16),
+ index * (CARD_WIDTH + 16),
+ (index + 1) * (CARD_WIDTH + 16),
+ ];
+
+ const bannerAnimatedStyle = useAnimatedStyle(() => ({
+ opacity: bannerOpacity.value,
+ }));
+
+ const logoAnimatedStyle = useAnimatedStyle(() => ({
+ opacity: logoOpacity.value,
+ }));
+
+ const genresAnimatedStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const cardOffset = index * (CARD_WIDTH + 16);
+ const distance = Math.abs(translateX - cardOffset);
+ const maxDistance = (CARD_WIDTH + 16) * 0.5; // Smaller threshold for smoother transition
+
+ // Hide genres when scrolling (not centered)
+ const progress = Math.min(distance / maxDistance, 1);
+ const opacity = 1 - progress; // Linear fade out
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
+
+ return {
+ opacity: clampedOpacity,
+ };
+ });
+
+ const actionsAnimatedStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const cardOffset = index * (CARD_WIDTH + 16);
+ const distance = Math.abs(translateX - cardOffset);
+ const maxDistance = (CARD_WIDTH + 16) * 0.5; // Smaller threshold for smoother transition
+
+ // Hide actions when scrolling (not centered)
+ const progress = Math.min(distance / maxDistance, 1);
+ const opacity = 1 - progress; // Linear fade out
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
+
+ return {
+ opacity: clampedOpacity,
+ };
+ });
+
+ // Scroll-based animations
+ const cardAnimatedStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const cardOffset = index * (CARD_WIDTH + 16);
+ const distance = Math.abs(translateX - cardOffset);
+ const maxDistance = CARD_WIDTH + 16;
+
+ // Scale animation based on distance from center
+ const scale = 1 - (distance / maxDistance) * 0.1;
+ const clampedScale = Math.max(0.9, Math.min(1, scale));
+
+ // Opacity animation for cards that are far from center
+ const opacity = 1 - (distance / maxDistance) * 0.3;
+ const clampedOpacity = Math.max(0.7, Math.min(1, opacity));
+
+ return {
+ transform: [{ scale: clampedScale }],
+ opacity: clampedOpacity,
+ };
+ });
+
+ const bannerParallaxStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const cardOffset = index * (CARD_WIDTH + 16);
+ const distance = translateX - cardOffset;
+
+ // Reduced parallax effect to prevent displacement
+ const parallaxOffset = distance * 0.05;
+
+ return {
+ transform: [{ translateX: parallaxOffset }],
+ };
+ });
+
+ const infoParallaxStyle = useAnimatedStyle(() => {
+ const translateX = scrollX.value;
+ const cardOffset = index * (CARD_WIDTH + 16);
+ const distance = Math.abs(translateX - cardOffset);
+ const maxDistance = CARD_WIDTH + 16;
+
+ // Hide info section when scrolling (not centered)
+ const progress = distance / maxDistance;
+ const opacity = 1 - progress * 2; // Fade out faster when scrolling
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
+
+ // Minimal parallax for info section to prevent displacement
+ const parallaxOffset = -(translateX - cardOffset) * 0.02;
+
+ return {
+ transform: [{ translateY: parallaxOffset }],
+ opacity: clampedOpacity,
+ };
+ });
+
+ useEffect(() => {
+ if (bannerLoaded) {
+ bannerOpacity.value = withTiming(1, {
+ duration: 250,
+ easing: Easing.out(Easing.ease)
+ });
+ }
+ }, [bannerLoaded]);
+
+ useEffect(() => {
+ if (logoLoaded) {
+ logoOpacity.value = withTiming(1, {
+ duration: 300,
+ easing: Easing.out(Easing.ease)
+ });
+ }
+ }, [logoLoaded]);
+
return (
-
- }>
-
-
-
-
-
- {item.logo && !logoFailed ? (
-
+ }>
+
+ {!bannerLoaded && (
+
+ )}
+
+ setBannerLoaded(true)}
+ />
+
+
- ) : (
-
- {item.name}
-
- )}
- {item.genres && (
-
+
+
+ {/* Static genres positioned absolutely over the card */}
+ {item.genres && (
+
+
{item.genres.slice(0, 3).join(' • ')}
-
- )}
-
+
+
+ )}
+ {/* Static action buttons positioned absolutely over the card */}
+
+
= memo(({ item, colors, logoFail
Info
-
+
-
-
+ {/* Static logo positioned absolutely over the card */}
+ {item.logo && !logoFailed && (
+
+
+ setLogoLoaded(true)}
+ onError={onLogoError}
+ />
+
+
+ )}
+ {/* Static title when no logo */}
+ {!item.logo || logoFailed ? (
+
+
+
+ {item.name}
+
+
+
+ ) : null}
+
+
);
});
@@ -542,6 +756,46 @@ const styles = StyleSheet.create({
marginLeft: 6,
fontSize: 14,
},
+ logoOverlay: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ paddingBottom: 80, // Position above genres and actions
+ },
+ titleOverlay: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ paddingBottom: 90, // Position above genres and actions
+ },
+ genresOverlay: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ paddingBottom: 65, // Position above actions
+ },
+ actionsOverlay: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ paddingBottom: 12, // Position at bottom
+ },
});
export default React.memo(HeroCarousel);
diff --git a/src/components/metadata/FloatingHeader.tsx b/src/components/metadata/FloatingHeader.tsx
index fd3a8ac0..ca7ffdd0 100644
--- a/src/components/metadata/FloatingHeader.tsx
+++ b/src/components/metadata/FloatingHeader.tsx
@@ -6,6 +6,7 @@ import {
TouchableOpacity,
Platform,
Dimensions,
+ Image,
} from 'react-native';
import { BlurView as ExpoBlurView } from 'expo-blur';
import { MaterialIcons, Feather } from '@expo/vector-icons';
@@ -24,7 +25,6 @@ if (Platform.OS === 'ios') {
liquidGlassAvailable = false;
}
}
-import FastImage from '@d11/react-native-fast-image';
import Animated, {
useAnimatedStyle,
interpolate,
@@ -49,6 +49,7 @@ interface FloatingHeaderProps {
headerElementsOpacity: SharedValue;
safeAreaTop: number;
setLogoLoadError: (error: boolean) => void;
+ stableLogoUri?: string | null;
}
const FloatingHeader: React.FC = ({
@@ -62,6 +63,7 @@ const FloatingHeader: React.FC = ({
headerElementsOpacity,
safeAreaTop,
setLogoLoadError,
+ stableLogoUri,
}) => {
const { currentTheme } = useTheme();
const [isHeaderInteractive, setIsHeaderInteractive] = React.useState(false);
@@ -111,13 +113,13 @@ const FloatingHeader: React.FC = ({
- {metadata.logo && !logoLoadError ? (
- {
- logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
+ logger.warn(`[FloatingHeader] Logo failed to load: ${stableLogoUri || metadata.logo}`);
setLogoLoadError(true);
}}
/>
@@ -155,13 +157,13 @@ const FloatingHeader: React.FC = ({
- {metadata.logo && !logoLoadError ? (
- {
- logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
+ logger.warn(`[FloatingHeader] Logo failed to load: ${stableLogoUri || metadata.logo}`);
setLogoLoadError(true);
}}
/>
@@ -202,10 +204,10 @@ const FloatingHeader: React.FC = ({
{metadata.logo && !logoLoadError ? (
- {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
setLogoLoadError(true);
diff --git a/src/components/metadata/HeroSection.tsx b/src/components/metadata/HeroSection.tsx
index 3d18114a..64fef14c 100644
--- a/src/components/metadata/HeroSection.tsx
+++ b/src/components/metadata/HeroSection.tsx
@@ -83,6 +83,7 @@ interface HeroSectionProps {
traktSynced?: boolean;
traktProgress?: number;
} | null;
+ onStableLogoUriChange?: (logoUri: string | null) => void;
type: 'movie' | 'series';
getEpisodeDetails: (episodeId: string) => { seasonNumber: string; episodeNumber: string; episodeName: string } | null;
handleShowStreams: () => void;
@@ -777,6 +778,7 @@ const HeroSection: React.FC = memo(({
buttonsTranslateY,
watchProgressOpacity,
watchProgress,
+ onStableLogoUriChange,
type,
getEpisodeDetails,
handleShowStreams,
@@ -832,7 +834,7 @@ const HeroSection: React.FC = memo(({
const titleCardTranslateY = useSharedValue(0);
const genreOpacity = useSharedValue(1);
- // Performance optimization: Cache theme colors
+ // Ultra-optimized theme colors with stable references
const themeColors = useMemo(() => ({
black: currentTheme.colors.black,
darkBackground: currentTheme.colors.darkBackground,
@@ -840,6 +842,15 @@ const HeroSection: React.FC = memo(({
text: currentTheme.colors.text
}), [currentTheme.colors.black, currentTheme.colors.darkBackground, currentTheme.colors.highEmphasis, currentTheme.colors.text]);
+ // Pre-calculated style objects for better performance
+ const staticStyles = useMemo(() => ({
+ heroWrapper: styles.heroWrapper,
+ heroSection: styles.heroSection,
+ absoluteFill: styles.absoluteFill,
+ thumbnailContainer: styles.thumbnailContainer,
+ thumbnailImage: styles.thumbnailImage,
+ }), []);
+
// Handle trailer preload completion
const handleTrailerPreloaded = useCallback(() => {
setTrailerPreloaded(true);
@@ -957,12 +968,14 @@ const HeroSection: React.FC = memo(({
if (metadata?.logo && metadata.logo !== stableLogoUri) {
setStableLogoUri(metadata.logo);
+ onStableLogoUriChange?.(metadata.logo);
setLogoHasLoadedSuccessfully(false); // Reset for new logo
logoLoadOpacity.value = 0; // reset fade for new logo
setShouldShowTextFallback(false);
} else if (!metadata?.logo && stableLogoUri) {
// Clear logo if metadata no longer has one
setStableLogoUri(null);
+ onStableLogoUriChange?.(null);
setLogoHasLoadedSuccessfully(false);
// Start a short grace period before showing text fallback
setShouldShowTextFallback(false);
@@ -1153,15 +1166,31 @@ const HeroSection: React.FC = memo(({
opacity: watchProgressOpacity.value,
}), []);
- // Enhanced backdrop with smooth loading animation
+ // Ultra-optimized backdrop with cached calculations and minimal worklet overhead
const backdropImageStyle = useAnimatedStyle(() => {
'worklet';
- const scale = 1 + (scrollY.value * 0.0001); // Micro scale effect
+ const scrollYValue = scrollY.value;
+
+ // Pre-calculated constants for better performance
+ const DEFAULT_ZOOM = 1.1;
+ const SCROLL_UP_MULTIPLIER = 0.002;
+ const SCROLL_DOWN_MULTIPLIER = 0.0001;
+ const MAX_SCALE = 1.4;
+ const PARALLAX_FACTOR = 0.3;
+
+ // Optimized scale calculation with minimal branching
+ const scrollUpScale = DEFAULT_ZOOM + Math.abs(scrollYValue) * SCROLL_UP_MULTIPLIER;
+ const scrollDownScale = DEFAULT_ZOOM + scrollYValue * SCROLL_DOWN_MULTIPLIER;
+ const scale = Math.min(scrollYValue < 0 ? scrollUpScale : scrollDownScale, MAX_SCALE);
+
+ // Single parallax calculation
+ const parallaxOffset = scrollYValue * PARALLAX_FACTOR;
return {
opacity: imageOpacity.value * imageLoadOpacity.value,
transform: [
- { scale: Math.min(scale, SCALE_FACTOR) } // Cap scale
+ { scale },
+ { translateY: parallaxOffset }
],
};
}, []);
@@ -1189,6 +1218,34 @@ const HeroSection: React.FC = memo(({
opacity: genreOpacity.value
}), []);
+ // Ultra-optimized trailer parallax with cached calculations
+ const trailerParallaxStyle = useAnimatedStyle(() => {
+ 'worklet';
+ const scrollYValue = scrollY.value;
+
+ // Pre-calculated constants for better performance
+ const DEFAULT_ZOOM = 1.0;
+ const SCROLL_UP_MULTIPLIER = 0.0015;
+ const SCROLL_DOWN_MULTIPLIER = 0.0001;
+ const MAX_SCALE = 1.25;
+ const PARALLAX_FACTOR = 0.2;
+
+ // Optimized scale calculation with minimal branching
+ const scrollUpScale = DEFAULT_ZOOM + Math.abs(scrollYValue) * SCROLL_UP_MULTIPLIER;
+ const scrollDownScale = DEFAULT_ZOOM + scrollYValue * SCROLL_DOWN_MULTIPLIER;
+ const scale = Math.min(scrollYValue < 0 ? scrollUpScale : scrollDownScale, MAX_SCALE);
+
+ // Single parallax calculation
+ const parallaxOffset = scrollYValue * PARALLAX_FACTOR;
+
+ return {
+ transform: [
+ { scale },
+ { translateY: parallaxOffset }
+ ],
+ };
+ }, []);
+
// Optimized genre rendering with lazy loading and memory management
const genreElements = useMemo(() => {
if (!shouldLoadSecondaryData || !metadata?.genres?.length) return null;
@@ -1336,27 +1393,31 @@ const HeroSection: React.FC = memo(({
}
}, [isFocused, setTrailerPlaying]);
- // Pause/resume trailer based on scroll with hysteresis and guard
+ // Ultra-optimized scroll-based pause/resume with cached calculations
useDerivedValue(() => {
'worklet';
try {
if (!scrollGuardEnabledSV.value || isFocusedSV.value === 0) return;
- const pauseThreshold = heroHeight.value * 0.7; // pause when beyond 70%
- const resumeThreshold = heroHeight.value * 0.4; // resume when back within 40%
-
+
+ // Pre-calculate thresholds for better performance
+ const pauseThreshold = heroHeight.value * 0.7;
+ const resumeThreshold = heroHeight.value * 0.4;
const y = scrollY.value;
+ const isPlaying = isPlayingSV.value === 1;
+ const isPausedByScroll = pausedByScrollSV.value === 1;
- if (y > pauseThreshold && isPlayingSV.value === 1 && pausedByScrollSV.value === 0) {
+ // Optimized pause/resume logic with minimal branching
+ if (y > pauseThreshold && isPlaying && !isPausedByScroll) {
pausedByScrollSV.value = 1;
runOnJS(setTrailerPlaying)(false);
isPlayingSV.value = 0;
- } else if (y < resumeThreshold && pausedByScrollSV.value === 1) {
+ } else if (y < resumeThreshold && isPausedByScroll) {
pausedByScrollSV.value = 0;
runOnJS(setTrailerPlaying)(true);
isPlayingSV.value = 1;
}
} catch (e) {
- // no-op
+ // Silent error handling for performance
}
});
@@ -1408,20 +1469,21 @@ const HeroSection: React.FC = memo(({
return (
-
- {/* Optimized Background */}
-
+
+
+ {/* Optimized Background */}
+
{/* Shimmer loading effect removed */}
- {/* Background thumbnail image - always rendered when available */}
+ {/* Background thumbnail image - always rendered when available with parallax */}
{shouldLoadSecondaryData && imageSource && !loadingBanner && (
-
= memo(({
{/* Hidden preload trailer player - loads in background */}
{shouldLoadSecondaryData && settings?.showTrailers && trailerUrl && !trailerLoading && !trailerError && !trailerPreloaded && (
-
+
= memo(({
)}
- {/* Visible trailer player - rendered on top with fade transition */}
+ {/* Visible trailer player - rendered on top with fade transition and parallax */}
{shouldLoadSecondaryData && settings?.showTrailers && trailerUrl && !trailerLoading && !trailerError && trailerPreloaded && (
-
+ }, trailerParallaxStyle]}>
= memo(({
/>
-
+
+
);
});
// Ultra-optimized styles
const styles = StyleSheet.create({
+ heroWrapper: {
+ width: '100%',
+ marginTop: -150, // Extend wrapper 150px above to accommodate thumbnail overflow
+ paddingTop: 150, // Add padding to maintain proper positioning
+ overflow: 'hidden', // This will clip the thumbnail overflow when scrolling
+ },
heroSection: {
width: '100%',
backgroundColor: '#000',
- overflow: 'hidden',
+ overflow: 'visible', // Allow thumbnail to extend within the wrapper
},
absoluteFill: {
@@ -1660,6 +1729,20 @@ const styles = StyleSheet.create({
right: 0,
bottom: 0,
},
+ thumbnailContainer: {
+ position: 'absolute',
+ top: 0, // Now positioned at the top of the wrapper (which extends 150px above)
+ left: 0,
+ right: 0,
+ bottom: 0,
+ },
+ thumbnailImage: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ },
backButtonContainer: {
position: 'absolute',
top: Platform.OS === 'android' ? 40 : 50,
diff --git a/src/components/metadata/TrailerModal.tsx b/src/components/metadata/TrailerModal.tsx
new file mode 100644
index 00000000..c18e131e
--- /dev/null
+++ b/src/components/metadata/TrailerModal.tsx
@@ -0,0 +1,467 @@
+import React, { useState, useEffect, useCallback, memo } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ Modal,
+ TouchableOpacity,
+ ActivityIndicator,
+ Dimensions,
+ Platform,
+ Alert,
+} from 'react-native';
+import { useTheme } from '../../contexts/ThemeContext';
+import { useTrailer } from '../../contexts/TrailerContext';
+import { logger } from '../../utils/logger';
+import TrailerService from '../../services/trailerService';
+import Video, { VideoRef, OnLoadData, OnProgressData } from 'react-native-video';
+
+const { width, height } = Dimensions.get('window');
+const isTablet = width >= 768;
+
+// Helper function to format trailer type
+const formatTrailerType = (type: string): string => {
+ switch (type) {
+ case 'Trailer':
+ return 'Official Trailer';
+ case 'Teaser':
+ return 'Teaser';
+ case 'Clip':
+ return 'Clip';
+ case 'Featurette':
+ return 'Featurette';
+ case 'Behind the Scenes':
+ return 'Behind the Scenes';
+ default:
+ return type;
+ }
+};
+
+interface TrailerVideo {
+ id: string;
+ key: string;
+ name: string;
+ site: string;
+ size: number;
+ type: string;
+ official: boolean;
+ published_at: string;
+}
+
+interface TrailerModalProps {
+ visible: boolean;
+ onClose: () => void;
+ trailer: TrailerVideo | null;
+ contentTitle: string;
+}
+
+const TrailerModal: React.FC = memo(({
+ visible,
+ onClose,
+ trailer,
+ contentTitle
+}) => {
+ const { currentTheme } = useTheme();
+ const { pauseTrailer, resumeTrailer } = useTrailer();
+ const videoRef = React.useRef(null);
+ const [trailerUrl, setTrailerUrl] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [isPlaying, setIsPlaying] = useState(false);
+ const [retryCount, setRetryCount] = useState(0);
+
+ // Load trailer when modal opens or trailer changes
+ useEffect(() => {
+ if (visible && trailer) {
+ loadTrailer();
+ } else {
+ // Reset state when modal closes
+ setTrailerUrl(null);
+ setLoading(false);
+ setError(null);
+ setIsPlaying(false);
+ setRetryCount(0);
+ }
+ }, [visible, trailer]);
+
+ const loadTrailer = useCallback(async () => {
+ if (!trailer) return;
+
+ // Pause hero section trailer when modal opens
+ try {
+ pauseTrailer();
+ logger.info('TrailerModal', 'Paused hero section trailer');
+ } catch (error) {
+ logger.warn('TrailerModal', 'Error pausing hero trailer:', error);
+ }
+
+ setLoading(true);
+ setError(null);
+ setTrailerUrl(null);
+ setRetryCount(0); // Reset retry count when starting fresh load
+
+ try {
+ const youtubeUrl = `https://www.youtube.com/watch?v=${trailer.key}`;
+
+ logger.info('TrailerModal', `Loading trailer: ${trailer.name} (${youtubeUrl})`);
+
+ // Use the direct YouTube URL method - much more efficient!
+ const directUrl = await TrailerService.getTrailerFromYouTubeUrl(
+ youtubeUrl,
+ `${contentTitle} - ${trailer.name}`,
+ new Date(trailer.published_at).getFullYear().toString()
+ );
+
+ if (directUrl) {
+ setTrailerUrl(directUrl);
+ setIsPlaying(true);
+ logger.info('TrailerModal', `Successfully loaded direct trailer URL for: ${trailer.name}`);
+ } else {
+ throw new Error('No streaming URL available');
+ }
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to load trailer';
+ setError(errorMessage);
+ setLoading(false);
+ logger.error('TrailerModal', 'Error loading trailer:', err);
+
+ Alert.alert(
+ 'Trailer Unavailable',
+ 'This trailer could not be loaded at this time. Please try again later.',
+ [{ text: 'OK', style: 'default' }]
+ );
+ }
+ }, [trailer, contentTitle, pauseTrailer]);
+
+ const handleClose = useCallback(() => {
+ setIsPlaying(false);
+
+ // Resume hero section trailer when modal closes
+ try {
+ resumeTrailer();
+ logger.info('TrailerModal', 'Resumed hero section trailer');
+ } catch (error) {
+ logger.warn('TrailerModal', 'Error resuming hero trailer:', error);
+ }
+
+ onClose();
+ }, [onClose, resumeTrailer]);
+
+ const handleTrailerError = useCallback(() => {
+ setError('Failed to play trailer');
+ setIsPlaying(false);
+ }, []);
+
+ // Handle video playback errors with retry logic
+ const handleVideoError = useCallback((error: any) => {
+ logger.error('TrailerModal', 'Video error:', error);
+
+ // Check if this is a permission/network error that might benefit from retry
+ const errorCode = error?.error?.code;
+ const isRetryableError = errorCode === -1102 || errorCode === -1009 || errorCode === -1005;
+
+ if (isRetryableError && retryCount < 2) {
+ // Silent retry - increment count and try again
+ logger.info('TrailerModal', `Retrying video load (attempt ${retryCount + 1}/2)`);
+ setRetryCount(prev => prev + 1);
+
+ // Small delay before retry to avoid rapid-fire attempts
+ setTimeout(() => {
+ if (videoRef.current) {
+ // Force video to reload by changing the source briefly
+ setTrailerUrl(null);
+ setTimeout(() => {
+ if (trailerUrl) {
+ setTrailerUrl(trailerUrl);
+ }
+ }, 100);
+ }
+ }, 1000);
+ return;
+ }
+
+ // After 2 retries or for non-retryable errors, show the error
+ logger.error('TrailerModal', 'Video error after retries or non-retryable:', error);
+ setError('Unable to play trailer. Please try again.');
+ setLoading(false);
+ }, [retryCount, trailerUrl]);
+
+ const handleTrailerEnd = useCallback(() => {
+ setIsPlaying(false);
+ }, []);
+
+ if (!visible || !trailer) return null;
+
+ const modalHeight = isTablet ? height * 0.8 : height * 0.7;
+ const modalWidth = isTablet ? width * 0.8 : width * 0.95;
+
+ return (
+
+
+
+ {/* Enhanced Header */}
+
+
+
+
+ {trailer.name}
+
+
+
+ {formatTrailerType(trailer.type)} • {new Date(trailer.published_at).getFullYear()}
+
+
+
+
+
+
+ Close
+
+
+
+
+ {/* Player Container */}
+
+ {loading && (
+
+
+
+ Loading trailer...
+
+
+ )}
+
+ {error && !loading && (
+
+
+ {error}
+
+
+ Try Again
+
+
+ )}
+
+ {/* Render the Video as soon as we have a URL; keep spinner overlay until onLoad */}
+ {trailerUrl && !error && (
+
+
+ )}
+
+
+ {/* Enhanced Footer */}
+
+
+
+ {contentTitle}
+
+
+
+
+
+
+ );
+});
+
+const styles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ backgroundColor: 'rgba(0,0,0,0.92)',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ modal: {
+ borderRadius: 20,
+ overflow: 'hidden',
+ elevation: 12,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 6 },
+ shadowOpacity: 0.4,
+ shadowRadius: 12,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.1)',
+ },
+
+ // Enhanced Header Styles
+ header: {
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ justifyContent: 'space-between',
+ paddingHorizontal: 20,
+ paddingVertical: 18,
+ borderBottomWidth: 1,
+ borderBottomColor: 'rgba(255,255,255,0.08)',
+ },
+ headerLeft: {
+ flexDirection: 'row',
+ flex: 1,
+ },
+ headerTextContainer: {
+ flex: 1,
+ gap: 4,
+ },
+ title: {
+ fontSize: 16,
+ fontWeight: '700',
+ lineHeight: 20,
+ color: '#fff',
+ },
+ headerMeta: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 8,
+ },
+ meta: {
+ fontSize: 12,
+ opacity: 0.7,
+ fontWeight: '500',
+ },
+ closeButton: {
+ paddingHorizontal: 12,
+ paddingVertical: 6,
+ borderRadius: 16,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ closeButtonText: {
+ fontSize: 14,
+ fontWeight: '600',
+ },
+ playerContainer: {
+ aspectRatio: 16 / 9,
+ backgroundColor: '#000',
+ position: 'relative',
+ },
+ loadingContainer: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#000',
+ gap: 16,
+ },
+ loadingText: {
+ fontSize: 14,
+ opacity: 0.8,
+ },
+ errorContainer: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#000',
+ padding: 20,
+ gap: 16,
+ },
+ errorText: {
+ fontSize: 14,
+ textAlign: 'center',
+ opacity: 0.8,
+ },
+ retryButton: {
+ paddingHorizontal: 20,
+ paddingVertical: 10,
+ borderRadius: 20,
+ },
+ retryButtonText: {
+ color: '#fff',
+ fontSize: 14,
+ fontWeight: '600',
+ },
+ playerWrapper: {
+ flex: 1,
+ },
+ player: {
+ flex: 1,
+ },
+ // Enhanced Footer Styles
+ footer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingHorizontal: 20,
+ paddingVertical: 16,
+ borderTopWidth: 1,
+ borderTopColor: 'rgba(255,255,255,0.08)',
+ },
+ footerContent: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ flex: 1,
+ },
+ footerText: {
+ fontSize: 13,
+ fontWeight: '500',
+ opacity: 0.8,
+ },
+ footerMeta: {
+ alignItems: 'flex-end',
+ },
+ footerMetaText: {
+ fontSize: 11,
+ opacity: 0.6,
+ fontWeight: '500',
+ },
+});
+
+export default TrailerModal;
diff --git a/src/components/metadata/TrailersSection.tsx b/src/components/metadata/TrailersSection.tsx
new file mode 100644
index 00000000..c059a59a
--- /dev/null
+++ b/src/components/metadata/TrailersSection.tsx
@@ -0,0 +1,860 @@
+import React, { useState, useEffect, useCallback, memo, useRef } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ ActivityIndicator,
+ Dimensions,
+ Alert,
+ Platform,
+ ScrollView,
+ Modal,
+} from 'react-native';
+import { MaterialIcons } from '@expo/vector-icons';
+import FastImage from '@d11/react-native-fast-image';
+import { useTheme } from '../../contexts/ThemeContext';
+import { useSettings } from '../../hooks/useSettings';
+import { useTrailer } from '../../contexts/TrailerContext';
+import { logger } from '../../utils/logger';
+import TrailerService from '../../services/trailerService';
+import TrailerModal from './TrailerModal';
+import Animated, { useSharedValue, withTiming, withDelay, useAnimatedStyle } from 'react-native-reanimated';
+
+const { width } = Dimensions.get('window');
+const isTablet = width >= 768;
+
+interface TrailerVideo {
+ id: string;
+ key: string;
+ name: string;
+ site: string;
+ size: number;
+ type: string;
+ official: boolean;
+ published_at: string;
+ seasonNumber: number | null;
+ displayName?: string;
+}
+
+interface TrailersSectionProps {
+ tmdbId: number | null;
+ type: 'movie' | 'tv';
+ contentId: string;
+ contentTitle: string;
+}
+
+interface CategorizedTrailers {
+ [key: string]: TrailerVideo[];
+}
+
+const TrailersSection: React.FC = memo(({
+ tmdbId,
+ type,
+ contentId,
+ contentTitle
+}) => {
+ const { currentTheme } = useTheme();
+ const { settings } = useSettings();
+ const { pauseTrailer } = useTrailer();
+ const [trailers, setTrailers] = useState({});
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [selectedTrailer, setSelectedTrailer] = useState(null);
+ const [modalVisible, setModalVisible] = useState(false);
+ const [selectedCategory, setSelectedCategory] = useState('Trailer');
+ const [dropdownVisible, setDropdownVisible] = useState(false);
+ const [backendAvailable, setBackendAvailable] = useState(null);
+
+ // Smooth reveal animation after trailers are fetched
+ const sectionOpacitySV = useSharedValue(0);
+ const sectionTranslateYSV = useSharedValue(8);
+ const hasAnimatedRef = useRef(false);
+
+ const sectionAnimatedStyle = useAnimatedStyle(() => ({
+ opacity: sectionOpacitySV.value,
+ transform: [{ translateY: sectionTranslateYSV.value }],
+ }));
+
+ // Reset animation state before a new fetch starts
+ const resetSectionAnimation = useCallback(() => {
+ hasAnimatedRef.current = false;
+ sectionOpacitySV.value = 0;
+ sectionTranslateYSV.value = 8;
+ }, [sectionOpacitySV, sectionTranslateYSV]);
+
+ // Trigger animation once, 500ms after trailers are available
+ const triggerSectionAnimation = useCallback(() => {
+ if (hasAnimatedRef.current) return;
+ hasAnimatedRef.current = true;
+ sectionOpacitySV.value = withDelay(500, withTiming(1, { duration: 400 }));
+ sectionTranslateYSV.value = withDelay(500, withTiming(0, { duration: 400 }));
+ }, [sectionOpacitySV, sectionTranslateYSV]);
+
+ // Check if trailer service backend is available
+ const checkBackendAvailability = useCallback(async (): Promise => {
+ try {
+ const serverStatus = TrailerService.getServerStatus();
+ const healthUrl = `${serverStatus.localUrl.replace('/trailer', '/health')}`;
+
+ const response = await fetch(healthUrl, {
+ method: 'GET',
+ signal: AbortSignal.timeout(3000), // 3 second timeout
+ });
+ const isAvailable = response.ok;
+ logger.info('TrailersSection', `Backend availability check: ${isAvailable ? 'AVAILABLE' : 'UNAVAILABLE'}`);
+ return isAvailable;
+ } catch (error) {
+ logger.warn('TrailersSection', 'Backend availability check failed:', error);
+ return false;
+ }
+ }, []);
+
+ // Fetch trailers from TMDB
+ useEffect(() => {
+ if (!tmdbId) return;
+
+ const initializeTrailers = async () => {
+ resetSectionAnimation();
+ // First check if backend is available
+ const available = await checkBackendAvailability();
+ setBackendAvailable(available);
+
+ if (!available) {
+ logger.warn('TrailersSection', 'Trailer service backend is not available - skipping trailer loading');
+ setLoading(false);
+ return;
+ }
+
+ // Backend is available, proceed with fetching trailers
+ await fetchTrailers();
+ };
+
+ const fetchTrailers = async () => {
+ setLoading(true);
+ setError(null);
+
+ try {
+ logger.info('TrailersSection', `Fetching trailers for TMDB ID: ${tmdbId}, type: ${type}`);
+
+ // First check if the movie/TV show exists
+ const basicEndpoint = type === 'movie'
+ ? `https://api.themoviedb.org/3/movie/${tmdbId}?api_key=d131017ccc6e5462a81c9304d21476de`
+ : `https://api.themoviedb.org/3/tv/${tmdbId}?api_key=d131017ccc6e5462a81c9304d21476de`;
+
+ const basicResponse = await fetch(basicEndpoint);
+ if (!basicResponse.ok) {
+ if (basicResponse.status === 404) {
+ // 404 on basic endpoint means TMDB ID doesn't exist - this is normal
+ logger.info('TrailersSection', `TMDB ID ${tmdbId} not found in TMDB (404) - skipping trailers`);
+ setTrailers({}); // Empty trailers - section won't render
+ return;
+ }
+ logger.error('TrailersSection', `TMDB basic endpoint failed: ${basicResponse.status} ${basicResponse.statusText}`);
+ setError(`Failed to verify content: ${basicResponse.status}`);
+ return;
+ }
+
+ let allVideos: any[] = [];
+
+ if (type === 'movie') {
+ // For movies, just fetch the main videos endpoint
+ const videosEndpoint = `https://api.themoviedb.org/3/movie/${tmdbId}/videos?api_key=d131017ccc6e5462a81c9304d21476de&language=en-US`;
+
+ logger.info('TrailersSection', `Fetching movie videos from: ${videosEndpoint}`);
+
+ const response = await fetch(videosEndpoint);
+ if (!response.ok) {
+ // 404 is normal - means no videos exist for this content
+ if (response.status === 404) {
+ logger.info('TrailersSection', `No videos found for movie TMDB ID ${tmdbId} (404 response)`);
+ setTrailers({}); // Empty trailers - section won't render
+ return;
+ }
+ logger.error('TrailersSection', `Videos endpoint failed: ${response.status} ${response.statusText}`);
+ throw new Error(`Failed to fetch trailers: ${response.status}`);
+ }
+
+ const data = await response.json();
+ allVideos = data.results || [];
+ logger.info('TrailersSection', `Received ${allVideos.length} videos for movie TMDB ID ${tmdbId}`);
+ } else {
+ // For TV shows, fetch both main TV videos and season-specific videos
+ logger.info('TrailersSection', `Fetching TV show videos and season trailers for TMDB ID ${tmdbId}`);
+
+ // Get TV show details to know how many seasons there are
+ const tvDetailsResponse = await fetch(basicEndpoint);
+ const tvDetails = await tvDetailsResponse.json();
+ const numberOfSeasons = tvDetails.number_of_seasons || 0;
+
+ logger.info('TrailersSection', `TV show has ${numberOfSeasons} seasons`);
+
+ // Fetch main TV show videos
+ const tvVideosEndpoint = `https://api.themoviedb.org/3/tv/${tmdbId}/videos?api_key=d131017ccc6e5462a81c9304d21476de&language=en-US`;
+ const tvResponse = await fetch(tvVideosEndpoint);
+
+ if (tvResponse.ok) {
+ const tvData = await tvResponse.json();
+ // Add season info to main TV videos
+ const mainVideos = (tvData.results || []).map((video: any) => ({
+ ...video,
+ seasonNumber: null as number | null, // null indicates main TV show videos
+ displayName: video.name
+ }));
+ allVideos.push(...mainVideos);
+ logger.info('TrailersSection', `Received ${mainVideos.length} main TV videos`);
+ }
+
+ // Fetch videos from each season (skip season 0 which is specials)
+ const seasonPromises = [];
+ for (let seasonNum = 1; seasonNum <= numberOfSeasons; seasonNum++) {
+ seasonPromises.push(
+ fetch(`https://api.themoviedb.org/3/tv/${tmdbId}/season/${seasonNum}/videos?api_key=d131017ccc6e5462a81c9304d21476de&language=en-US`)
+ .then(res => res.json())
+ .then(data => ({
+ seasonNumber: seasonNum,
+ videos: data.results || []
+ }))
+ .catch(err => {
+ logger.warn('TrailersSection', `Failed to fetch season ${seasonNum} videos:`, err);
+ return { seasonNumber: seasonNum, videos: [] };
+ })
+ );
+ }
+
+ const seasonResults = await Promise.all(seasonPromises);
+
+ // Add season videos to the collection
+ seasonResults.forEach(result => {
+ if (result.videos.length > 0) {
+ const seasonVideos = result.videos.map((video: any) => ({
+ ...video,
+ seasonNumber: result.seasonNumber as number | null,
+ displayName: `Season ${result.seasonNumber} - ${video.name}`
+ }));
+ allVideos.push(...seasonVideos);
+ logger.info('TrailersSection', `Season ${result.seasonNumber}: ${result.videos.length} videos`);
+ }
+ });
+
+ const totalSeasonVideos = seasonResults.reduce((sum, result) => sum + result.videos.length, 0);
+ logger.info('TrailersSection', `Total videos collected: ${allVideos.length} (main: ${allVideos.filter(v => v.seasonNumber === null).length}, seasons: ${totalSeasonVideos})`);
+ }
+
+ const categorized = categorizeTrailers(allVideos);
+ const totalVideos = Object.values(categorized).reduce((sum, videos) => sum + videos.length, 0);
+
+ if (totalVideos === 0) {
+ logger.info('TrailersSection', `No videos found for TMDB ID ${tmdbId} - this is normal`);
+ setTrailers({}); // No trailers available
+ setSelectedCategory(''); // No category selected
+ } else {
+ logger.info('TrailersSection', `Categorized ${totalVideos} videos into ${Object.keys(categorized).length} categories`);
+ setTrailers(categorized);
+ // Trigger smooth reveal after 1.5s since we have content
+ triggerSectionAnimation();
+
+ // Auto-select the first available category, preferring "Trailer"
+ const availableCategories = Object.keys(categorized);
+ const preferredCategory = availableCategories.includes('Trailer') ? 'Trailer' :
+ availableCategories.includes('Teaser') ? 'Teaser' : availableCategories[0];
+ setSelectedCategory(preferredCategory);
+ }
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to load trailers';
+ setError(errorMessage);
+ logger.error('TrailersSection', 'Error fetching trailers:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ initializeTrailers();
+ }, [tmdbId, type, checkBackendAvailability]);
+
+ // Categorize trailers by type
+ const categorizeTrailers = (videos: any[]): CategorizedTrailers => {
+ const categories: CategorizedTrailers = {};
+
+ videos.forEach(video => {
+ if (video.site !== 'YouTube') return; // Only YouTube videos
+
+ const category = video.type;
+ if (!categories[category]) {
+ categories[category] = [];
+ }
+ categories[category].push(video);
+ });
+
+ // Sort within each category: season trailers first (newest seasons), then main series, official first, then by date
+ Object.keys(categories).forEach(category => {
+ categories[category].sort((a, b) => {
+ // Season trailers come before main series trailers
+ if (a.seasonNumber !== null && b.seasonNumber === null) return -1;
+ if (a.seasonNumber === null && b.seasonNumber !== null) return 1;
+
+ // If both have season numbers, sort by season number (newest seasons first)
+ if (a.seasonNumber !== null && b.seasonNumber !== null) {
+ if (a.seasonNumber !== b.seasonNumber) {
+ return b.seasonNumber - a.seasonNumber; // Higher season numbers first
+ }
+ }
+
+ // Official trailers come first within the same season/main series group
+ if (a.official && !b.official) return -1;
+ if (!a.official && b.official) return 1;
+
+ // If both are official or both are not, sort by published date (newest first)
+ return new Date(b.published_at).getTime() - new Date(a.published_at).getTime();
+ });
+ });
+
+ // Sort categories: "Trailer" category first, then categories with official trailers, then alphabetically
+ const sortedCategories = Object.keys(categories).sort((a, b) => {
+ // "Trailer" category always comes first
+ if (a === 'Trailer') return -1;
+ if (b === 'Trailer') return 1;
+
+ const aHasOfficial = categories[a].some(trailer => trailer.official);
+ const bHasOfficial = categories[b].some(trailer => trailer.official);
+
+ // Categories with official trailers come first (after Trailer)
+ if (aHasOfficial && !bHasOfficial) return -1;
+ if (!aHasOfficial && bHasOfficial) return 1;
+
+ // If both have or don't have official trailers, sort alphabetically
+ return a.localeCompare(b);
+ });
+
+ // Create new object with sorted categories
+ const sortedCategoriesObj: CategorizedTrailers = {};
+ sortedCategories.forEach(category => {
+ sortedCategoriesObj[category] = categories[category];
+ });
+
+ return sortedCategoriesObj;
+ };
+
+ // Handle trailer selection
+ const handleTrailerPress = (trailer: TrailerVideo) => {
+ // Pause hero section trailer when modal opens
+ try {
+ pauseTrailer();
+ } catch (error) {
+ logger.warn('TrailersSection', 'Error pausing hero trailer:', error);
+ }
+
+ setSelectedTrailer(trailer);
+ setModalVisible(true);
+ };
+
+ // Handle modal close
+ const handleModalClose = () => {
+ setModalVisible(false);
+ setSelectedTrailer(null);
+ // Note: Hero trailer will resume automatically when modal closes
+ // The HeroSection component handles resuming based on scroll position
+ };
+
+ // Handle category selection
+ const handleCategorySelect = (category: string) => {
+ setSelectedCategory(category);
+ setDropdownVisible(false);
+ };
+
+ // Toggle dropdown
+ const toggleDropdown = () => {
+ setDropdownVisible(!dropdownVisible);
+ };
+
+ // Get thumbnail URL for YouTube video
+ const getYouTubeThumbnail = (videoId: string, quality: 'default' | 'hq' | 'maxres' = 'hq') => {
+ const qualities = {
+ default: `https://img.youtube.com/vi/${videoId}/default.jpg`,
+ hq: `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
+ maxres: `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`
+ };
+ return qualities[quality];
+ };
+
+ // Format trailer type for display
+ const formatTrailerType = (type: string): string => {
+ switch (type) {
+ case 'Trailer':
+ return 'Official Trailers';
+ case 'Teaser':
+ return 'Teasers';
+ case 'Clip':
+ return 'Clips & Scenes';
+ case 'Featurette':
+ return 'Featurettes';
+ case 'Behind the Scenes':
+ return 'Behind the Scenes';
+ default:
+ return type;
+ }
+ };
+
+ // Get icon for trailer type
+ const getTrailerTypeIcon = (type: string): string => {
+ switch (type) {
+ case 'Trailer':
+ return 'movie';
+ case 'Teaser':
+ return 'videocam';
+ case 'Clip':
+ return 'content-cut';
+ case 'Featurette':
+ return 'featured-video';
+ case 'Behind the Scenes':
+ return 'camera';
+ default:
+ return 'play-circle-outline';
+ }
+ };
+
+ if (!tmdbId) {
+ return null; // Don't show if no TMDB ID
+ }
+
+ // Don't render if backend availability is still being checked or backend is unavailable
+ if (backendAvailable === null || backendAvailable === false) {
+ return null;
+ }
+
+ // Don't render if TMDB enrichment is disabled
+ if (!settings?.enrichMetadataWithTMDB) {
+ return null;
+ }
+
+ if (loading) {
+ return null;
+ }
+
+ if (error) {
+ return null;
+ }
+
+ const trailerCategories = Object.keys(trailers);
+ const totalVideos = Object.values(trailers).reduce((sum, videos) => sum + videos.length, 0);
+
+ // Don't show section if no trailers (this is normal for many movies/TV shows)
+ if (trailerCategories.length === 0 || totalVideos === 0) {
+ // In development, show a subtle indicator that the section checked but found no trailers
+ if (__DEV__) {
+ return (
+
+
+
+
+ Trailers
+
+
+
+
+ No trailers available
+
+
+
+ );
+ }
+ return null;
+ }
+
+ return (
+
+ {/* Enhanced Header with Category Selector */}
+
+
+ Trailers & Videos
+
+
+ {/* Category Selector - Right Aligned */}
+ {trailerCategories.length > 0 && selectedCategory && (
+
+
+ {formatTrailerType(selectedCategory)}
+
+
+
+ )}
+
+
+ {/* Category Dropdown Modal */}
+ setDropdownVisible(false)}
+ >
+ setDropdownVisible(false)}
+ >
+
+ {trailerCategories.map(category => (
+ handleCategorySelect(category)}
+ activeOpacity={0.7}
+ >
+
+
+
+
+
+ {formatTrailerType(category)}
+
+
+ {trailers[category].length}
+
+
+
+ ))}
+
+
+
+
+ {/* Selected Category Trailers */}
+ {selectedCategory && trailers[selectedCategory] && (
+
+ {/* Trailers Horizontal Scroll */}
+
+ {trailers[selectedCategory].map((trailer, index) => (
+ handleTrailerPress(trailer)}
+ activeOpacity={0.9}
+ >
+ {/* Thumbnail with Gradient Overlay */}
+
+
+ {/* Subtle Gradient Overlay */}
+
+
+
+ {/* Trailer Info */}
+
+
+ {trailer.displayName || trailer.name}
+
+
+ {new Date(trailer.published_at).getFullYear()}
+
+
+
+ ))}
+ {/* Scroll Indicator - shows when there are more items to scroll */}
+ {trailers[selectedCategory].length > (isTablet ? 4 : 3) && (
+
+
+
+ )}
+
+
+ )}
+
+ {/* Trailer Modal */}
+
+
+ );
+});
+
+const styles = StyleSheet.create({
+ container: {
+ paddingHorizontal: 16,
+ marginTop: 24,
+ marginBottom: 16,
+ },
+ // Enhanced Header Styles
+ header: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'flex-start',
+ marginBottom: 0,
+ gap: 12,
+ },
+ headerTitle: {
+ fontSize: 20,
+ fontWeight: '700',
+ letterSpacing: 0.5,
+ },
+
+ // Category Selector Styles
+ categorySelector: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ borderWidth: 1,
+ borderRadius: 16,
+ paddingHorizontal: 10,
+ paddingVertical: 5,
+ backgroundColor: 'rgba(255,255,255,0.03)',
+ gap: 6,
+ maxWidth: 160, // Limit maximum width to prevent overflow
+ },
+ categorySelectorText: {
+ fontSize: 12,
+ fontWeight: '600',
+ maxWidth: 120, // Limit text width
+ },
+
+ // Dropdown Styles
+ dropdownOverlay: {
+ flex: 1,
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingHorizontal: 20,
+ },
+ dropdownContainer: {
+ width: '100%',
+ maxWidth: 320,
+ borderRadius: 16,
+ borderWidth: 1,
+ overflow: 'hidden',
+ elevation: 8,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.3,
+ shadowRadius: 8,
+ },
+ dropdownItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingHorizontal: 16,
+ paddingVertical: 14,
+ borderBottomWidth: 1,
+ borderBottomColor: 'rgba(255,255,255,0.05)',
+ },
+ dropdownItemContent: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 12,
+ flex: 1,
+ },
+ dropdownItemText: {
+ fontSize: 16,
+ flex: 1,
+ },
+ dropdownItemCount: {
+ fontSize: 12,
+ opacity: 0.7,
+ backgroundColor: 'rgba(255,255,255,0.1)',
+ paddingHorizontal: 8,
+ paddingVertical: 4,
+ borderRadius: 10,
+ minWidth: 24,
+ textAlign: 'center',
+ },
+
+ // Selected Category Content
+ selectedCategoryContent: {
+ marginTop: 16,
+ },
+
+ // Category Section Styles
+ categorySection: {
+ gap: 12,
+ position: 'relative', // For scroll indicator positioning
+ },
+ categoryHeader: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ categoryTitleContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 8,
+ },
+ categoryIconContainer: {
+ width: 28,
+ height: 28,
+ borderRadius: 8,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ categoryTitle: {
+ fontSize: 16,
+ fontWeight: '600',
+ },
+ categoryBadge: {
+ borderRadius: 12,
+ paddingHorizontal: 8,
+ paddingVertical: 4,
+ minWidth: 24,
+ alignItems: 'center',
+ },
+ categoryBadgeText: {
+ fontSize: 12,
+ fontWeight: '600',
+ },
+
+ // Trailers Scroll View
+ trailersScrollView: {
+ marginHorizontal: -4, // Compensate for padding
+ },
+ trailersScrollContent: {
+ paddingHorizontal: 4, // Restore padding for first/last items
+ gap: 12,
+ paddingRight: 20, // Extra padding at end for scroll indicator
+ },
+
+ // Enhanced Trailer Card Styles
+ trailerCard: {
+ width: isTablet ? 200 : 170,
+ backgroundColor: 'rgba(255,255,255,0.03)',
+ borderRadius: 16,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.08)',
+ overflow: 'hidden',
+ elevation: 2,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 1 },
+ shadowOpacity: 0.1,
+ shadowRadius: 2,
+ },
+
+ // Thumbnail Styles
+ thumbnailWrapper: {
+ position: 'relative',
+ aspectRatio: 16 / 9,
+ },
+ thumbnail: {
+ width: '100%',
+ height: '100%',
+ borderTopLeftRadius: 16,
+ borderTopRightRadius: 16,
+ },
+ thumbnailGradient: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ backgroundColor: 'rgba(0,0,0,0.2)',
+ borderTopLeftRadius: 16,
+ borderTopRightRadius: 16,
+ },
+
+
+
+ // Trailer Info Styles
+ trailerInfo: {
+ padding: 12,
+ },
+ trailerTitle: {
+ fontSize: 12,
+ fontWeight: '600',
+ lineHeight: 16,
+ marginBottom: 4,
+ },
+ trailerMeta: {
+ fontSize: 10,
+ opacity: 0.7,
+ fontWeight: '500',
+ },
+
+ // Loading and Error States
+ loadingContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: 32,
+ gap: 12,
+ },
+ loadingText: {
+ fontSize: 14,
+ opacity: 0.7,
+ },
+ errorContainer: {
+ alignItems: 'center',
+ paddingVertical: 32,
+ gap: 8,
+ },
+ errorText: {
+ fontSize: 14,
+ textAlign: 'center',
+ opacity: 0.7,
+ },
+
+ // Scroll Indicator
+ scrollIndicator: {
+ position: 'absolute',
+ right: 4,
+ top: '50%',
+ transform: [{ translateY: -10 }],
+ width: 24,
+ height: 20,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: 'rgba(0,0,0,0.3)',
+ borderRadius: 12,
+ },
+
+ // No Trailers State
+ noTrailersContainer: {
+ alignItems: 'center',
+ paddingVertical: 24,
+ },
+ noTrailersText: {
+ fontSize: 14,
+ opacity: 0.6,
+ fontStyle: 'italic',
+ },
+});
+
+export default TrailersSection;
diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx
index 0a89cdc7..2354da8e 100644
--- a/src/components/player/AndroidVideoPlayer.tsx
+++ b/src/components/player/AndroidVideoPlayer.tsx
@@ -86,7 +86,7 @@ const AndroidVideoPlayer: React.FC = () => {
}, [route.params]);
// TEMP: force React Native Video for testing (disable VLC)
const TEMP_FORCE_RNV = false;
- const TEMP_FORCE_VLC = true;
+ const TEMP_FORCE_VLC = false;
const useVLC = Platform.OS === 'android' && !TEMP_FORCE_RNV && (TEMP_FORCE_VLC || forceVlc);
// Log player selection
@@ -1614,7 +1614,7 @@ const AndroidVideoPlayer: React.FC = () => {
resizeModes = ['contain', 'cover'];
} else {
// On Android with VLC backend, only 'none' (original) and 'cover' (client-side crop)
- resizeModes = useVLC ? ['none', 'cover'] : ['contain', 'cover', 'none'];
+ resizeModes = useVLC ? ['none', 'cover'] : ['cover', 'none'];
}
const currentIndex = resizeModes.indexOf(resizeMode);
diff --git a/src/components/player/KSPlayerCore.tsx b/src/components/player/KSPlayerCore.tsx
index 94e65628..688af143 100644
--- a/src/components/player/KSPlayerCore.tsx
+++ b/src/components/player/KSPlayerCore.tsx
@@ -110,7 +110,7 @@ const KSPlayerCore: React.FC = () => {
const [selectedAudioTrack, setSelectedAudioTrack] = useState(null);
const [textTracks, setTextTracks] = useState([]);
const [selectedTextTrack, setSelectedTextTrack] = useState(-1);
- const [resizeMode, setResizeMode] = useState('stretch');
+ const [resizeMode, setResizeMode] = useState('contain');
const [buffered, setBuffered] = useState(0);
const [seekPosition, setSeekPosition] = useState(null);
const ksPlayerRef = useRef(null);
diff --git a/src/components/video/TrailerPlayer.tsx b/src/components/video/TrailerPlayer.tsx
index 5ce62332..6dafac8e 100644
--- a/src/components/video/TrailerPlayer.tsx
+++ b/src/components/video/TrailerPlayer.tsx
@@ -20,6 +20,7 @@ import Animated, {
runOnJS,
} from 'react-native-reanimated';
import { useTheme } from '../../contexts/ThemeContext';
+import { useTrailer } from '../../contexts/TrailerContext';
import { logger } from '../../utils/logger';
const { width, height } = Dimensions.get('window');
@@ -57,6 +58,7 @@ const TrailerPlayer = React.forwardRef(({
hideControls = false,
}, ref) => {
const { currentTheme } = useTheme();
+ const { isTrailerPlaying: globalTrailerPlaying } = useTrailer();
const videoRef = useRef(null);
const [isLoading, setIsLoading] = useState(true);
@@ -146,6 +148,22 @@ const TrailerPlayer = React.forwardRef(({
}
}, [autoPlay, isComponentMounted]);
+ // Respond to global trailer state changes (e.g., when modal opens)
+ useEffect(() => {
+ if (isComponentMounted) {
+ // If global trailer is paused, pause this trailer too
+ if (!globalTrailerPlaying && isPlaying) {
+ logger.info('TrailerPlayer', 'Global trailer paused - pausing this trailer');
+ setIsPlaying(false);
+ }
+ // If global trailer is resumed and autoPlay is enabled, resume this trailer
+ else if (globalTrailerPlaying && !isPlaying && autoPlay) {
+ logger.info('TrailerPlayer', 'Global trailer resumed - resuming this trailer');
+ setIsPlaying(true);
+ }
+ }
+ }, [globalTrailerPlaying, isPlaying, autoPlay, isComponentMounted]);
+
const showControlsWithTimeout = useCallback(() => {
if (!isComponentMounted) return;
diff --git a/src/hooks/useMetadata.ts b/src/hooks/useMetadata.ts
index fb66db71..3c9ad638 100644
--- a/src/hooks/useMetadata.ts
+++ b/src/hooks/useMetadata.ts
@@ -107,28 +107,6 @@ interface UseMetadataReturn {
imdbId: string | null;
scraperStatuses: ScraperStatus[];
activeFetchingScrapers: string[];
- clearScraperCache: () => Promise;
- invalidateScraperCache: (scraperId: string) => Promise;
- invalidateContentCache: (type: string, tmdbId: string, season?: number, episode?: number) => Promise;
- getScraperCacheStats: () => Promise<{
- local: {
- totalEntries: number;
- totalSize: number;
- oldestEntry: number | null;
- newestEntry: number | null;
- };
- global: {
- totalEntries: number;
- totalSize: number;
- oldestEntry: number | null;
- newestEntry: number | null;
- hitRate: number;
- };
- combined: {
- totalEntries: number;
- hitRate: number;
- };
- }>;
}
export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadataReturn => {
@@ -287,9 +265,9 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
// Optimize streams before storing
const optimizedStreams = optimizeStreams(streams);
streamCountRef.current += optimizedStreams.length;
-
+
if (__DEV__) logger.log(`📊 [${logPrefix}:${sourceName}] Optimized ${streams.length} → ${optimizedStreams.length} streams, total: ${streamCountRef.current}`);
-
+
// Use debounced update to prevent rapid state changes
debouncedStreamUpdate(() => {
const updateState = (prevState: GroupedStreams): GroupedStreams => {
@@ -302,7 +280,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
}
};
};
-
+
// Track response order for addons
setAddonResponseOrder(prevOrder => {
if (!prevOrder.includes(addonId)) {
@@ -310,7 +288,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
}
return prevOrder;
});
-
+
if (isEpisode) {
setEpisodeStreams(updateState);
setLoadingEpisodeStreams(false);
@@ -320,7 +298,38 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
}
});
} else {
- if (__DEV__) logger.log(`🤷 [${logPrefix}:${sourceName}] No streams found for addon ${addonName} (${addonId})`);
+ // Even providers with no streams should be added to the streams object
+ // This ensures streamsEmpty becomes false and UI shows available streams progressively
+ if (__DEV__) logger.log(`🤷 [${logPrefix}:${sourceName}] No streams found for addon ${addonName} (${addonId})`);
+
+ debouncedStreamUpdate(() => {
+ const updateState = (prevState: GroupedStreams): GroupedStreams => {
+ if (__DEV__) logger.log(`🔄 [${logPrefix}:${sourceName}] Adding empty provider ${addonName} (${addonId}) to state`);
+ return {
+ ...prevState,
+ [addonId]: {
+ addonName: addonName,
+ streams: [] // Empty array for providers with no streams
+ }
+ };
+ };
+
+ // Track response order for addons
+ setAddonResponseOrder(prevOrder => {
+ if (!prevOrder.includes(addonId)) {
+ return [...prevOrder, addonId];
+ }
+ return prevOrder;
+ });
+
+ if (isEpisode) {
+ setEpisodeStreams(updateState);
+ setLoadingEpisodeStreams(false);
+ } else {
+ setGroupedStreams(updateState);
+ setLoadingStreams(false);
+ }
+ });
}
} else {
// Handle case where callback provides null streams without error (e.g., empty results)
@@ -1974,36 +1983,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
};
}, [cleanupStreams]);
- // Cache management methods
- const clearScraperCache = useCallback(async () => {
- await localScraperService.clearScraperCache();
- }, []);
-
- const invalidateScraperCache = useCallback(async (scraperId: string) => {
- await localScraperService.invalidateScraperCache(scraperId);
- }, []);
-
- const invalidateContentCache = useCallback(async (type: string, tmdbId: string, season?: number, episode?: number) => {
- await localScraperService.invalidateContentCache(type, tmdbId, season, episode);
- }, []);
-
- const getScraperCacheStats = useCallback(async () => {
- const localStats = await localScraperService.getCacheStats();
- return {
- local: localStats.local,
- global: {
- totalEntries: 0,
- totalSize: 0,
- oldestEntry: null,
- newestEntry: null,
- hitRate: 0
- },
- combined: {
- totalEntries: localStats.local.totalEntries,
- hitRate: 0
- }
- };
- }, []);
return {
metadata,
@@ -2038,9 +2017,5 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
imdbId,
scraperStatuses,
activeFetchingScrapers,
- clearScraperCache,
- invalidateScraperCache,
- invalidateContentCache,
- getScraperCacheStats,
};
};
\ No newline at end of file
diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx
index 32219897..c8057995 100644
--- a/src/navigation/AppNavigator.tsx
+++ b/src/navigation/AppNavigator.tsx
@@ -672,7 +672,7 @@ const MainTabs = () => {
bottom: 0,
left: 0,
right: 0,
- height: 85,
+ height: 85 + insets.bottom,
backgroundColor: 'transparent',
overflow: 'hidden',
}}>
@@ -722,7 +722,7 @@ const MainTabs = () => {
{
// Dynamically require to avoid impacting Android bundle
const { createNativeBottomTabNavigator } = require('@bottom-tabs/react-navigation');
const IOSTab = createNativeBottomTabNavigator();
+ const downloadsEnabled = appSettings?.enableDownloads !== false;
return (
@@ -828,6 +829,8 @@ const MainTabs = () => {
backgroundColor="transparent"
/>
{
tabBarIcon: () => ({ sfSymbol: 'magnifyingglass' }),
}}
/>
- {appSettings?.enableDownloads !== false && (
+ {downloadsEnabled && (
{
backgroundColor="transparent"
translucent
/>
- {
ListFooterComponent={ListFooterComponent}
onEndReached={handleLoadMoreCatalogs}
onEndReachedThreshold={0.6}
- removeClippedSubviews={true}
- scrollEventThrottle={64}
+ recycleItems={true}
+ maintainVisibleContentPosition
onScroll={handleScroll}
/>
{/* Toasts are rendered globally at root */}
diff --git a/src/screens/MetadataScreen.tsx b/src/screens/MetadataScreen.tsx
index d37128ac..40043dea 100644
--- a/src/screens/MetadataScreen.tsx
+++ b/src/screens/MetadataScreen.tsx
@@ -26,6 +26,7 @@ import { MovieContent } from '../components/metadata/MovieContent';
import { MoreLikeThisSection } from '../components/metadata/MoreLikeThisSection';
import { RatingsSection } from '../components/metadata/RatingsSection';
import { CommentsSection, CommentBottomSheet } from '../components/metadata/CommentsSection';
+import TrailersSection from '../components/metadata/TrailersSection';
import { RouteParams, Episode } from '../types/metadata';
import Animated, {
useAnimatedStyle,
@@ -210,6 +211,9 @@ const MetadataScreen: React.FC = () => {
const watchProgressData = useWatchProgress(id, Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series', episodeId, episodes);
const assetData = useMetadataAssets(metadata, id, type, imdbId, settings, setMetadata);
const animations = useMetadataAnimations(safeAreaTop, watchProgressData.watchProgress);
+
+ // Stable logo URI from HeroSection
+ const [stableLogoUri, setStableLogoUri] = React.useState(null);
// Extract dominant color from hero image for dynamic background
const heroImageUri = useMemo(() => {
@@ -869,7 +873,7 @@ const MetadataScreen: React.FC = () => {
{metadata && (
<>
{/* Floating Header - Optimized */}
- {
headerElementsOpacity={animations.headerElementsOpacity}
safeAreaTop={safeAreaTop}
setLogoLoadError={assetData.setLogoLoadError}
+ stableLogoUri={stableLogoUri}
/>
{
watchProgressOpacity={animations.watchProgressOpacity}
watchProgressWidth={animations.watchProgressWidth}
watchProgress={watchProgressData.watchProgress}
+ onStableLogoUriChange={setStableLogoUri}
type={Object.keys(groupedEpisodes).length > 0 ? 'series' : type as 'movie' | 'series'}
getEpisodeDetails={watchProgressData.getEpisodeDetails}
handleShowStreams={handleShowStreams}
@@ -992,6 +998,16 @@ const MetadataScreen: React.FC = () => {
)}
+ {/* Trailers Section - Lazy loaded */}
+ {shouldLoadSecondaryData && tmdbId && settings.enrichMetadataWithTMDB && (
+ 0 ? 'tv' : 'movie'}
+ contentId={id}
+ contentTitle={metadata?.name || (metadata as any)?.title || 'Unknown'}
+ />
+ )}
+
{/* Comments Section - Lazy loaded */}
{shouldLoadSecondaryData && imdbId && (
- onPress()}
- activeOpacity={0.7}
- >
-
-
+
{settings?.enableDownloads !== false && (
;
- expiredScrapers: string[];
- allExpired: boolean;
- source: 'local';
-}
-
-export interface HybridCacheStats {
- local: {
- totalEntries: number;
- totalSize: number;
- oldestEntry: number | null;
- newestEntry: number | null;
- };
-}
-
-class HybridCacheService {
- private static instance: HybridCacheService;
- // Global caching removed; local-only
-
- private constructor() {}
-
- public static getInstance(): HybridCacheService {
- if (!HybridCacheService.instance) {
- HybridCacheService.instance = new HybridCacheService();
- }
- return HybridCacheService.instance;
- }
-
- /**
- * Get cached results (local-only)
- */
- async getCachedResults(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number,
- userSettings?: { enableLocalScrapers?: boolean; enabledScrapers?: Set }
- ): Promise {
- try {
- // Filter function to check if scraper is enabled for current user
- const isScraperEnabled = (scraperId: string): boolean => {
- if (!userSettings?.enableLocalScrapers) return false;
- if (userSettings?.enabledScrapers) {
- return userSettings.enabledScrapers.has(scraperId);
- }
- // If no specific scraper settings, assume all are enabled if local scrapers are enabled
- return true;
- };
-
- // Local cache only
- const localResults = await localScraperCacheService.getCachedResults(type, tmdbId, season, episode);
-
- // Filter results based on user settings
- const filteredLocalResults = {
- ...localResults,
- validResults: localResults.validResults.filter(result => isScraperEnabled(result.scraperId)),
- expiredScrapers: localResults.expiredScrapers.filter(scraperId => isScraperEnabled(scraperId))
- };
-
- logger.log(`[HybridCache] Using local cache: ${filteredLocalResults.validResults.length} results (filtered from ${localResults.validResults.length})`);
- return {
- ...filteredLocalResults,
- source: 'local'
- };
-
- } catch (error) {
- logger.error('[HybridCache] Error getting cached results:', error);
- return {
- validResults: [],
- expiredScrapers: [],
- allExpired: true,
- source: 'local'
- };
- }
- }
-
- /**
- * Cache results (local-only)
- */
- async cacheResults(
- type: string,
- tmdbId: string,
- results: Array<{
- scraperId: string;
- scraperName: string;
- streams: Stream[] | null;
- error: Error | null;
- }>,
- season?: number,
- episode?: number
- ): Promise {
- try {
- // Cache in local storage
- const localPromises = results.map(result =>
- localScraperCacheService.cacheScraperResult(
- type, tmdbId, result.scraperId, result.scraperName,
- result.streams, result.error, season, episode
- )
- );
- await Promise.all(localPromises);
- logger.log(`[HybridCache] Cached ${results.length} results in local cache`);
-
- } catch (error) {
- logger.error('[HybridCache] Error caching results:', error);
- }
- }
-
- /**
- * Cache a single scraper result
- */
- async cacheScraperResult(
- type: string,
- tmdbId: string,
- scraperId: string,
- scraperName: string,
- streams: Stream[] | null,
- error: Error | null,
- season?: number,
- episode?: number
- ): Promise {
- await this.cacheResults(type, tmdbId, [{
- scraperId,
- scraperName,
- streams,
- error
- }], season, episode);
- }
-
- /**
- * Get list of scrapers that need to be re-run (expired, failed, or not cached)
- */
- async getScrapersToRerun(
- type: string,
- tmdbId: string,
- availableScrapers: Array<{ id: string; name: string }>,
- season?: number,
- episode?: number,
- userSettings?: { enableLocalScrapers?: boolean; enabledScrapers?: Set }
- ): Promise {
- const { validResults, expiredScrapers } = await this.getCachedResults(type, tmdbId, season, episode, userSettings);
-
- const validScraperIds = new Set(validResults.map(r => r.scraperId));
- const expiredScraperIds = new Set(expiredScrapers);
-
- // Get scrapers that previously failed (returned no streams)
- const failedScraperIds = new Set(
- validResults
- .filter(r => !r.success || r.streams.length === 0)
- .map(r => r.scraperId)
- );
-
- // Return scrapers that are:
- // 1. Not cached at all
- // 2. Expired
- // 3. Previously failed (regardless of cache status)
- const scrapersToRerun = availableScrapers
- .filter(scraper =>
- !validScraperIds.has(scraper.id) ||
- expiredScraperIds.has(scraper.id) ||
- failedScraperIds.has(scraper.id)
- )
- .map(scraper => scraper.id);
-
- logger.log(`[HybridCache] Scrapers to re-run: ${scrapersToRerun.join(', ')} (not cached: ${availableScrapers.filter(s => !validScraperIds.has(s.id)).length}, expired: ${expiredScrapers.length}, failed: ${failedScraperIds.size})`);
-
- return scrapersToRerun;
- }
-
- /**
- * Get all valid cached streams
- */
- async getCachedStreams(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number,
- userSettings?: { enableLocalScrapers?: boolean; enabledScrapers?: Set }
- ): Promise {
- const { validResults } = await this.getCachedResults(type, tmdbId, season, episode, userSettings);
-
- // Flatten all valid streams
- const allStreams: Stream[] = [];
- for (const result of validResults) {
- if (result.success && result.streams) {
- allStreams.push(...result.streams);
- }
- }
-
- return allStreams;
- }
-
- /**
- * Invalidate cache for specific content (local-only)
- */
- async invalidateContent(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number
- ): Promise {
- try {
- await localScraperCacheService.invalidateContent(type, tmdbId, season, episode);
- logger.log(`[HybridCache] Invalidated cache for ${type}:${tmdbId}`);
- } catch (error) {
- logger.error('[HybridCache] Error invalidating cache:', error);
- }
- }
-
- /**
- * Invalidate cache for specific scraper (local-only)
- */
- async invalidateScraper(scraperId: string): Promise {
- try {
- await localScraperCacheService.invalidateScraper(scraperId);
- logger.log(`[HybridCache] Invalidated cache for scraper ${scraperId}`);
- } catch (error) {
- logger.error('[HybridCache] Error invalidating scraper cache:', error);
- }
- }
-
- /**
- * Clear all cached results (local-only)
- */
- async clearAllCache(): Promise {
- try {
- await localScraperCacheService.clearAllCache();
- logger.log('[HybridCache] Cleared all local cache');
- } catch (error) {
- logger.error('[HybridCache] Error clearing cache:', error);
- }
- }
-
- /**
- * Get cache statistics (local-only)
- */
- async getCacheStats(): Promise {
- try {
- const localStats = await localScraperCacheService.getCacheStats();
- return { local: localStats };
- } catch (error) {
- logger.error('[HybridCache] Error getting cache stats:', error);
- return { local: { totalEntries: 0, totalSize: 0, oldestEntry: null, newestEntry: null } };
- }
- }
-
- /**
- * Clean up old entries (local-only)
- */
- async cleanupOldEntries(): Promise {
- try {
- await localScraperCacheService.clearAllCache();
- logger.log('[HybridCache] Cleaned up old entries');
- } catch (error) {
- logger.error('[HybridCache] Error cleaning up old entries:', error);
- }
- }
-
- // Configuration APIs removed; local-only
-}
-
-export const hybridCacheService = HybridCacheService.getInstance();
-export default hybridCacheService;
diff --git a/src/services/localScraperCacheService.ts b/src/services/localScraperCacheService.ts
deleted file mode 100644
index e00eb6e9..00000000
--- a/src/services/localScraperCacheService.ts
+++ /dev/null
@@ -1,437 +0,0 @@
-import AsyncStorage from '@react-native-async-storage/async-storage';
-import { logger } from '../utils/logger';
-import { Stream } from '../types/streams';
-
-export interface CachedScraperResult {
- streams: Stream[];
- timestamp: number;
- success: boolean;
- error?: string;
- scraperId: string;
- scraperName: string;
-}
-
-export interface CachedContentResult {
- contentKey: string; // e.g., "movie:123" or "tv:123:1:2"
- results: CachedScraperResult[];
- timestamp: number;
- ttl: number;
-}
-
-class LocalScraperCacheService {
- private static instance: LocalScraperCacheService;
- private readonly CACHE_KEY_PREFIX = 'local-scraper-cache';
- private readonly DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes default TTL
- private readonly MAX_CACHE_SIZE = 200; // Maximum number of cached content items
- private readonly FAILED_RETRY_TTL_MS = 5 * 60 * 1000; // 5 minutes for failed scrapers
- private readonly SUCCESS_TTL_MS = 60 * 60 * 1000; // 1 hour for successful scrapers
-
- private constructor() {}
-
- public static getInstance(): LocalScraperCacheService {
- if (!LocalScraperCacheService.instance) {
- LocalScraperCacheService.instance = new LocalScraperCacheService();
- }
- return LocalScraperCacheService.instance;
- }
-
- /**
- * Generate cache key for content
- */
- private getContentKey(type: string, tmdbId: string, season?: number, episode?: number): string {
- if (season !== undefined && episode !== undefined) {
- return `${type}:${tmdbId}:${season}:${episode}`;
- }
- return `${type}:${tmdbId}`;
- }
-
- /**
- * Generate AsyncStorage key for cached content
- */
- private getStorageKey(contentKey: string): string {
- return `${this.CACHE_KEY_PREFIX}:${contentKey}`;
- }
-
- /**
- * Check if cached result is still valid based on TTL
- */
- private isCacheValid(timestamp: number, ttl: number): boolean {
- return Date.now() - timestamp < ttl;
- }
-
- /**
- * Get cached results for content, filtering out expired results
- */
- async getCachedResults(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number
- ): Promise<{
- validResults: CachedScraperResult[];
- expiredScrapers: string[];
- allExpired: boolean;
- }> {
- try {
- const contentKey = this.getContentKey(type, tmdbId, season, episode);
- const storageKey = this.getStorageKey(contentKey);
-
- const cachedData = await AsyncStorage.getItem(storageKey);
- if (!cachedData) {
- return {
- validResults: [],
- expiredScrapers: [],
- allExpired: true
- };
- }
-
- const parsed: CachedContentResult = JSON.parse(cachedData);
-
- // Check if the entire cache entry is expired
- if (!this.isCacheValid(parsed.timestamp, parsed.ttl)) {
- // Remove expired entry
- await AsyncStorage.removeItem(storageKey);
- return {
- validResults: [],
- expiredScrapers: parsed.results.map(r => r.scraperId),
- allExpired: true
- };
- }
-
- // Filter valid results and identify expired scrapers
- const validResults: CachedScraperResult[] = [];
- const expiredScrapers: string[] = [];
-
- for (const result of parsed.results) {
- // Use different TTL based on success/failure
- const ttl = result.success ? this.SUCCESS_TTL_MS : this.FAILED_RETRY_TTL_MS;
-
- if (this.isCacheValid(result.timestamp, ttl)) {
- validResults.push(result);
- } else {
- expiredScrapers.push(result.scraperId);
- }
- }
-
- logger.log(`[LocalScraperCache] Retrieved ${validResults.length} valid results, ${expiredScrapers.length} expired scrapers for ${contentKey}`);
-
- return {
- validResults,
- expiredScrapers,
- allExpired: validResults.length === 0
- };
-
- } catch (error) {
- logger.error('[LocalScraperCache] Error getting cached results:', error);
- return {
- validResults: [],
- expiredScrapers: [],
- allExpired: true
- };
- }
- }
-
- /**
- * Cache results for specific scrapers
- */
- async cacheResults(
- type: string,
- tmdbId: string,
- results: CachedScraperResult[],
- season?: number,
- episode?: number
- ): Promise {
- try {
- const contentKey = this.getContentKey(type, tmdbId, season, episode);
- const storageKey = this.getStorageKey(contentKey);
-
- // Get existing cached data
- const existingData = await AsyncStorage.getItem(storageKey);
- let cachedContent: CachedContentResult;
-
- if (existingData) {
- cachedContent = JSON.parse(existingData);
-
- // Update existing results or add new ones
- for (const newResult of results) {
- const existingIndex = cachedContent.results.findIndex(r => r.scraperId === newResult.scraperId);
- if (existingIndex >= 0) {
- // Update existing result
- cachedContent.results[existingIndex] = newResult;
- } else {
- // Add new result
- cachedContent.results.push(newResult);
- }
- }
- } else {
- // Create new cache entry
- cachedContent = {
- contentKey,
- results,
- timestamp: Date.now(),
- ttl: this.DEFAULT_TTL_MS
- };
- }
-
- // Update timestamp
- cachedContent.timestamp = Date.now();
-
- // Store updated cache
- await AsyncStorage.setItem(storageKey, JSON.stringify(cachedContent));
-
- // Clean up old cache entries if we exceed the limit
- await this.cleanupOldEntries();
-
- logger.log(`[LocalScraperCache] Cached ${results.length} results for ${contentKey}`);
-
- } catch (error) {
- logger.error('[LocalScraperCache] Error caching results:', error);
- }
- }
-
- /**
- * Cache a single scraper result
- */
- async cacheScraperResult(
- type: string,
- tmdbId: string,
- scraperId: string,
- scraperName: string,
- streams: Stream[] | null,
- error: Error | null,
- season?: number,
- episode?: number
- ): Promise {
- const result: CachedScraperResult = {
- streams: streams || [],
- timestamp: Date.now(),
- success: !error && streams !== null,
- error: error?.message,
- scraperId,
- scraperName
- };
-
- await this.cacheResults(type, tmdbId, [result], season, episode);
- }
-
- /**
- * Get list of scrapers that need to be re-run (expired, failed, or not cached)
- */
- async getScrapersToRerun(
- type: string,
- tmdbId: string,
- availableScrapers: Array<{ id: string; name: string }>,
- season?: number,
- episode?: number
- ): Promise {
- const { validResults, expiredScrapers } = await this.getCachedResults(type, tmdbId, season, episode);
-
- const validScraperIds = new Set(validResults.map(r => r.scraperId));
- const expiredScraperIds = new Set(expiredScrapers);
-
- // Get scrapers that previously failed (returned no streams)
- const failedScraperIds = new Set(
- validResults
- .filter(r => !r.success || r.streams.length === 0)
- .map(r => r.scraperId)
- );
-
- // Return scrapers that are:
- // 1. Not cached at all
- // 2. Expired
- // 3. Previously failed (regardless of cache status)
- const scrapersToRerun = availableScrapers
- .filter(scraper =>
- !validScraperIds.has(scraper.id) ||
- expiredScraperIds.has(scraper.id) ||
- failedScraperIds.has(scraper.id)
- )
- .map(scraper => scraper.id);
-
- logger.log(`[LocalScraperCache] Scrapers to re-run: ${scrapersToRerun.join(', ')} (not cached: ${availableScrapers.filter(s => !validScraperIds.has(s.id)).length}, expired: ${expiredScrapers.length}, failed: ${failedScraperIds.size})`);
-
- return scrapersToRerun;
- }
-
- /**
- * Get all valid cached streams for content
- */
- async getCachedStreams(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number
- ): Promise {
- const { validResults } = await this.getCachedResults(type, tmdbId, season, episode);
-
- // Flatten all valid streams
- const allStreams: Stream[] = [];
- for (const result of validResults) {
- if (result.success && result.streams) {
- allStreams.push(...result.streams);
- }
- }
-
- return allStreams;
- }
-
- /**
- * Invalidate cache for specific content
- */
- async invalidateContent(
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number
- ): Promise {
- try {
- const contentKey = this.getContentKey(type, tmdbId, season, episode);
- const storageKey = this.getStorageKey(contentKey);
-
- await AsyncStorage.removeItem(storageKey);
- logger.log(`[LocalScraperCache] Invalidated cache for ${contentKey}`);
- } catch (error) {
- logger.error('[LocalScraperCache] Error invalidating cache:', error);
- }
- }
-
- /**
- * Invalidate cache for specific scraper across all content
- */
- async invalidateScraper(scraperId: string): Promise {
- try {
- const keys = await AsyncStorage.getAllKeys();
- const cacheKeys = keys.filter(key => key.startsWith(this.CACHE_KEY_PREFIX));
-
- for (const key of cacheKeys) {
- const cachedData = await AsyncStorage.getItem(key);
- if (cachedData) {
- const parsed: CachedContentResult = JSON.parse(cachedData);
-
- // Remove results from this scraper
- parsed.results = parsed.results.filter(r => r.scraperId !== scraperId);
-
- if (parsed.results.length === 0) {
- // Remove entire cache entry if no results left
- await AsyncStorage.removeItem(key);
- } else {
- // Update cache with remaining results
- await AsyncStorage.setItem(key, JSON.stringify(parsed));
- }
- }
- }
-
- logger.log(`[LocalScraperCache] Invalidated cache for scraper ${scraperId}`);
- } catch (error) {
- logger.error('[LocalScraperCache] Error invalidating scraper cache:', error);
- }
- }
-
- /**
- * Clear all cached results
- */
- async clearAllCache(): Promise {
- try {
- const keys = await AsyncStorage.getAllKeys();
- const cacheKeys = keys.filter(key => key.startsWith(this.CACHE_KEY_PREFIX));
-
- await AsyncStorage.multiRemove(cacheKeys);
- logger.log(`[LocalScraperCache] Cleared ${cacheKeys.length} cache entries`);
- } catch (error) {
- logger.error('[LocalScraperCache] Error clearing cache:', error);
- }
- }
-
- /**
- * Clean up old cache entries to stay within size limit
- */
- private async cleanupOldEntries(): Promise {
- try {
- const keys = await AsyncStorage.getAllKeys();
- const cacheKeys = keys.filter(key => key.startsWith(this.CACHE_KEY_PREFIX));
-
- if (cacheKeys.length <= this.MAX_CACHE_SIZE) {
- return; // No cleanup needed
- }
-
- // Get all cache entries with their timestamps
- const entriesWithTimestamps = await Promise.all(
- cacheKeys.map(async (key) => {
- const data = await AsyncStorage.getItem(key);
- if (data) {
- const parsed: CachedContentResult = JSON.parse(data);
- return { key, timestamp: parsed.timestamp };
- }
- return { key, timestamp: 0 };
- })
- );
-
- // Sort by timestamp (oldest first)
- entriesWithTimestamps.sort((a, b) => a.timestamp - b.timestamp);
-
- // Remove oldest entries
- const entriesToRemove = entriesWithTimestamps.slice(0, cacheKeys.length - this.MAX_CACHE_SIZE);
- const keysToRemove = entriesToRemove.map(entry => entry.key);
-
- if (keysToRemove.length > 0) {
- await AsyncStorage.multiRemove(keysToRemove);
- logger.log(`[LocalScraperCache] Cleaned up ${keysToRemove.length} old cache entries`);
- }
-
- } catch (error) {
- logger.error('[LocalScraperCache] Error cleaning up cache:', error);
- }
- }
-
- /**
- * Get cache statistics
- */
- async getCacheStats(): Promise<{
- totalEntries: number;
- totalSize: number;
- oldestEntry: number | null;
- newestEntry: number | null;
- }> {
- try {
- const keys = await AsyncStorage.getAllKeys();
- const cacheKeys = keys.filter(key => key.startsWith(this.CACHE_KEY_PREFIX));
-
- let totalSize = 0;
- let oldestTimestamp: number | null = null;
- let newestTimestamp: number | null = null;
-
- for (const key of cacheKeys) {
- const data = await AsyncStorage.getItem(key);
- if (data) {
- totalSize += data.length;
- const parsed: CachedContentResult = JSON.parse(data);
-
- if (oldestTimestamp === null || parsed.timestamp < oldestTimestamp) {
- oldestTimestamp = parsed.timestamp;
- }
- if (newestTimestamp === null || parsed.timestamp > newestTimestamp) {
- newestTimestamp = parsed.timestamp;
- }
- }
- }
-
- return {
- totalEntries: cacheKeys.length,
- totalSize,
- oldestEntry: oldestTimestamp,
- newestEntry: newestTimestamp
- };
- } catch (error) {
- logger.error('[LocalScraperCache] Error getting cache stats:', error);
- return {
- totalEntries: 0,
- totalSize: 0,
- oldestEntry: null,
- newestEntry: null
- };
- }
- }
-}
-
-export const localScraperCacheService = LocalScraperCacheService.getInstance();
-export default localScraperCacheService;
diff --git a/src/services/localScraperService.ts b/src/services/localScraperService.ts
index e8f1467a..ff7e801f 100644
--- a/src/services/localScraperService.ts
+++ b/src/services/localScraperService.ts
@@ -4,8 +4,6 @@ import { Platform } from 'react-native';
import { logger } from '../utils/logger';
import { Stream } from '../types/streams';
import { cacheService } from './cacheService';
-import { localScraperCacheService } from './localScraperCacheService';
-import { hybridCacheService } from './hybridCacheService';
import CryptoJS from 'crypto-js';
// Types for local scrapers
@@ -862,86 +860,44 @@ class LocalScraperService {
}
}
- // Execute scrapers for streams with caching
+ // Execute scrapers for streams
async getStreams(type: string, tmdbId: string, season?: number, episode?: number, callback?: ScraperCallback): Promise {
await this.ensureInitialized();
-
+
// Get available scrapers from manifest (respects manifestEnabled)
const availableScrapers = await this.getAvailableScrapers();
const enabledScrapers = availableScrapers
- .filter(scraper =>
- scraper.enabled &&
- scraper.manifestEnabled !== false &&
+ .filter(scraper =>
+ scraper.enabled &&
+ scraper.manifestEnabled !== false &&
scraper.supportedTypes.includes(type as 'movie' | 'tv')
);
-
+
if (enabledScrapers.length === 0) {
logger.log('[LocalScraperService] No enabled scrapers found for type:', type);
return;
}
- // Get current user settings for enabled scrapers
- const userSettings = await this.getUserScraperSettings();
-
- // Check cache for existing results (hybrid: global first, then local)
- const { validResults, expiredScrapers, allExpired, source } = await hybridCacheService.getCachedResults(type, tmdbId, season, episode, userSettings);
-
- // Immediately return cached results for valid scrapers
- if (validResults.length > 0) {
- logger.log(`[LocalScraperService] Returning ${validResults.length} cached results for ${type}:${tmdbId} (source: ${source})`);
-
- for (const cachedResult of validResults) {
- if (cachedResult.success && cachedResult.streams.length > 0) {
- // Streams are already in the correct format, just pass them through
- if (callback) {
- callback(cachedResult.streams, cachedResult.scraperId, cachedResult.scraperName, null);
- }
- } else if (callback) {
- // Return error for failed cached results
- const error = cachedResult.error ? new Error(cachedResult.error) : new Error('Scraper failed');
- callback(null, cachedResult.scraperId, cachedResult.scraperName, error);
- }
- }
- }
-
- // Determine which scrapers need to be re-run
- const scrapersToRerun = enabledScrapers.filter(scraper => {
- const hasValidResult = validResults.some(r => r.scraperId === scraper.id);
- const isExpired = expiredScrapers.includes(scraper.id);
- const hasFailedResult = validResults.some(r => r.scraperId === scraper.id && (!r.success || r.streams.length === 0));
-
- return !hasValidResult || isExpired || hasFailedResult;
- });
-
- if (scrapersToRerun.length === 0) {
- logger.log('[LocalScraperService] All scrapers have valid cached results');
- return;
- }
-
- logger.log(`[LocalScraperService] Re-running ${scrapersToRerun.length} scrapers for ${type}:${tmdbId}`, {
- totalEnabled: enabledScrapers.length,
- expired: expiredScrapers.length,
- failed: validResults.filter(r => !r.success || r.streams.length === 0).length,
- notCached: enabledScrapers.length - validResults.length,
- scrapersToRerun: scrapersToRerun.map(s => s.name)
+ logger.log(`[LocalScraperService] Executing ${enabledScrapers.length} scrapers for ${type}:${tmdbId}`, {
+ scrapers: enabledScrapers.map(s => s.name)
});
// Generate a lightweight request id for tracing
const requestId = `rs_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
- // Execute only scrapers that need to be re-run
- for (const scraper of scrapersToRerun) {
- this.executeScraperWithCaching(scraper, type, tmdbId, season, episode, callback, requestId);
+ // Execute all enabled scrapers
+ for (const scraper of enabledScrapers) {
+ this.executeScraper(scraper, type, tmdbId, season, episode, callback, requestId);
}
}
- // Execute individual scraper with caching
- private async executeScraperWithCaching(
- scraper: ScraperInfo,
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number,
+ // Execute individual scraper
+ private async executeScraper(
+ scraper: ScraperInfo,
+ type: string,
+ tmdbId: string,
+ season?: number,
+ episode?: number,
callback?: ScraperCallback,
requestId?: string
): Promise {
@@ -950,10 +906,10 @@ class LocalScraperService {
if (!code) {
throw new Error(`No code found for scraper ${scraper.id}`);
}
-
+
// Load per-scraper settings
const scraperSettings = await this.getScraperSettings(scraper.id);
-
+
// Build single-flight key
const flightKey = `${scraper.id}|${type}|${tmdbId}|${season ?? ''}|${episode ?? ''}`;
@@ -980,60 +936,23 @@ class LocalScraperService {
}
const results = await promise;
-
+
// Convert results to Nuvio Stream format
const streams = this.convertToStreams(results, scraper);
-
- // Cache the successful result (hybrid: both local and global)
- await hybridCacheService.cacheScraperResult(
- type,
- tmdbId,
- scraper.id,
- scraper.name,
- streams,
- null,
- season,
- episode
- );
-
+
if (callback) {
callback(streams, scraper.id, scraper.name, null);
}
-
+
} catch (error) {
logger.error('[LocalScraperService] Scraper', scraper.name, 'failed:', error);
-
- // Cache the failed result (hybrid: both local and global)
- await hybridCacheService.cacheScraperResult(
- type,
- tmdbId,
- scraper.id,
- scraper.name,
- null,
- error as Error,
- season,
- episode
- );
-
+
if (callback) {
callback(null, scraper.id, scraper.name, error as Error);
}
}
}
- // Execute individual scraper (legacy method - kept for compatibility)
- private async executeScraper(
- scraper: ScraperInfo,
- type: string,
- tmdbId: string,
- season?: number,
- episode?: number,
- callback?: ScraperCallback,
- requestId?: string
- ): Promise {
- // Delegate to the caching version
- return this.executeScraperWithCaching(scraper, type, tmdbId, season, episode, callback, requestId);
- }
// Execute scraper code in sandboxed environment
private async executeSandboxed(code: string, params: any): Promise {
@@ -1161,7 +1080,7 @@ class LocalScraperService {
...options.headers
},
data: options.body,
- timeout: 60000,
+ timeout: 120000, // Increased to 2 minutes for complex scrapers
validateStatus: () => true // Don't throw on HTTP error status codes
};
@@ -1201,7 +1120,7 @@ class LocalScraperService {
},
// Add axios for HTTP requests
axios: axios.create({
- timeout: 30000,
+ timeout: 120000, // Increased to 2 minutes for complex scrapers
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
@@ -1217,27 +1136,29 @@ class LocalScraperService {
SCRAPER_ID: params?.scraperId
};
- // Execute the scraper code without timeout
+ // Execute the scraper code with 1 minute timeout
+ const SCRAPER_EXECUTION_TIMEOUT_MS = 60000; // 1 minute
+
const executionPromise = new Promise((resolve, reject) => {
try {
// Create function from code
const func = new Function('sandbox', 'params', 'PRIMARY_KEY', 'TMDB_API_KEY', `
const { console, setTimeout, clearTimeout, Promise, JSON, Date, Math, parseInt, parseFloat, encodeURIComponent, decodeURIComponent, require, axios, fetch, module, exports, global, URL_VALIDATION_ENABLED, SCRAPER_SETTINGS, SCRAPER_ID } = sandbox;
-
+
// Inject MovieBox constants into global scope
global.PRIMARY_KEY = PRIMARY_KEY;
global.TMDB_API_KEY = TMDB_API_KEY;
window.PRIMARY_KEY = PRIMARY_KEY;
window.TMDB_API_KEY = TMDB_API_KEY;
-
+
// Expose per-scraper context to plugin globals
global.SCRAPER_SETTINGS = SCRAPER_SETTINGS;
global.SCRAPER_ID = SCRAPER_ID;
window.SCRAPER_SETTINGS = SCRAPER_SETTINGS;
window.SCRAPER_ID = SCRAPER_ID;
-
+
${code}
-
+
// Call the main function (assuming it's exported)
if (typeof getStreams === 'function') {
return getStreams(params.tmdbId, params.mediaType, params.season, params.episode);
@@ -1249,9 +1170,9 @@ class LocalScraperService {
throw new Error('No getStreams function found in scraper');
}
`);
-
+
const result = func(sandbox, params, MOVIEBOX_PRIMARY_KEY, MOVIEBOX_TMDB_API_KEY);
-
+
// Handle both sync and async results
if (result && typeof result.then === 'function') {
result.then(resolve).catch(reject);
@@ -1262,8 +1183,14 @@ class LocalScraperService {
reject(error);
}
});
-
- return await executionPromise;
+
+ // Apply 1-minute timeout to prevent hanging scrapers
+ return await Promise.race([
+ executionPromise,
+ new Promise((_, reject) =>
+ setTimeout(() => reject(new Error(`Scraper execution timed out after ${SCRAPER_EXECUTION_TIMEOUT_MS}ms`)), SCRAPER_EXECUTION_TIMEOUT_MS)
+ )
+ ]);
} catch (error) {
logger.error('[LocalScraperService] Sandbox execution failed:', error);
@@ -1365,6 +1292,19 @@ class LocalScraperService {
// Check if local scrapers are available
async hasScrapers(): Promise {
await this.ensureInitialized();
+
+ // Get user settings to check if local scrapers are enabled
+ const userSettings = await this.getUserScraperSettings();
+ if (!userSettings.enableLocalScrapers) {
+ return false;
+ }
+
+ // Check if there are any enabled scrapers based on user settings
+ if (userSettings.enabledScrapers && userSettings.enabledScrapers.size > 0) {
+ return true;
+ }
+
+ // Fallback: check if any scrapers are enabled in the internal state
return Array.from(this.installedScrapers.values()).some(scraper => scraper.enabled);
}
@@ -1384,8 +1324,11 @@ class LocalScraperService {
};
}
- // Get user settings from AsyncStorage
- const settingsData = await AsyncStorage.getItem('app_settings');
+ // Get user settings from AsyncStorage (scoped with fallback)
+ const scope = (await AsyncStorage.getItem('@user:current')) || 'local';
+ const scopedSettingsJson = await AsyncStorage.getItem(`@user:${scope}:app_settings`);
+ const legacySettingsJson = await AsyncStorage.getItem('app_settings');
+ const settingsData = scopedSettingsJson || legacySettingsJson;
const settings = settingsData ? JSON.parse(settingsData) : {};
// Get enabled scrapers based on current user settings
@@ -1408,32 +1351,6 @@ class LocalScraperService {
}
}
- // Cache management methods (hybrid: local + global)
- async clearScraperCache(): Promise {
- await hybridCacheService.clearAllCache();
- logger.log('[LocalScraperService] Cleared all scraper cache (local + global)');
- }
-
- async invalidateScraperCache(scraperId: string): Promise {
- await hybridCacheService.invalidateScraper(scraperId);
- logger.log('[LocalScraperService] Invalidated cache for scraper:', scraperId);
- }
-
- async invalidateContentCache(type: string, tmdbId: string, season?: number, episode?: number): Promise {
- await hybridCacheService.invalidateContent(type, tmdbId, season, episode);
- logger.log('[LocalScraperService] Invalidated cache for content:', `${type}:${tmdbId}`);
- }
-
- async getCacheStats(): Promise<{
- local: {
- totalEntries: number;
- totalSize: number;
- oldestEntry: number | null;
- newestEntry: number | null;
- };
- }> {
- return await hybridCacheService.getCacheStats();
- }
}
export const localScraperService = LocalScraperService.getInstance();
diff --git a/src/services/stremioService.ts b/src/services/stremioService.ts
index 49593b08..c1a39478 100644
--- a/src/services/stremioService.ts
+++ b/src/services/stremioService.ts
@@ -1235,13 +1235,16 @@ class StremioService {
// Execute local scrapers asynchronously with TMDB ID (when available)
if (tmdbId) {
localScraperService.getStreams(scraperType, tmdbId, season, episode, (streams, scraperId, scraperName, error) => {
- if (error) {
- if (callback) {
+ // Always call callback to ensure UI updates, regardless of result
+ if (callback) {
+ if (error) {
callback(null, scraperId, scraperName, error);
- }
- } else if (streams && streams.length > 0) {
- if (callback) {
+ } else if (streams && streams.length > 0) {
callback(streams, scraperId, scraperName, null);
+ } else {
+ // Handle case where scraper completed successfully but returned no streams
+ // This ensures the scraper is removed from "fetching" state in UI
+ callback([], scraperId, scraperName, null);
}
}
});
diff --git a/src/services/trailerService.ts b/src/services/trailerService.ts
index c72aaecb..fa4c7366 100644
--- a/src/services/trailerService.ts
+++ b/src/services/trailerService.ts
@@ -7,10 +7,16 @@ export interface TrailerData {
}
export class TrailerService {
- private static readonly XPRIME_URL = 'https://db.xprime.tv/trailers';
- private static readonly LOCAL_SERVER_URL = 'http://192.168.1.11:3001/trailer';
- private static readonly AUTO_SEARCH_URL = 'http://192.168.1.11:3001/search-trailer';
- private static readonly TIMEOUT = 10000; // 10 seconds
+ // Environment-configurable values (Expo public env)
+ private static readonly ENV_LOCAL_BASE = process.env.EXPO_PUBLIC_TRAILER_LOCAL_BASE || 'http://46.62.173.157:3001';
+ private static readonly ENV_LOCAL_TRAILER_PATH = process.env.EXPO_PUBLIC_TRAILER_LOCAL_TRAILER_PATH || '/trailer';
+ private static readonly ENV_LOCAL_SEARCH_PATH = process.env.EXPO_PUBLIC_TRAILER_LOCAL_SEARCH_PATH || '/search-trailer';
+ private static readonly ENV_XPRIME_URL = process.env.EXPO_PUBLIC_XPRIME_URL || 'https://db.xprime.tv/trailers';
+
+ private static readonly XPRIME_URL = TrailerService.ENV_XPRIME_URL;
+ private static readonly LOCAL_SERVER_URL = `${TrailerService.ENV_LOCAL_BASE}${TrailerService.ENV_LOCAL_TRAILER_PATH}`;
+ private static readonly AUTO_SEARCH_URL = `${TrailerService.ENV_LOCAL_BASE}${TrailerService.ENV_LOCAL_SEARCH_PATH}`;
+ private static readonly TIMEOUT = 20000; // 20 seconds
private static readonly USE_LOCAL_SERVER = true; // Toggle between local and XPrime
/**
@@ -22,10 +28,12 @@ export class TrailerService {
* @returns Promise - The trailer URL or null if not found
*/
static async getTrailerUrl(title: string, year: number, tmdbId?: string, type?: 'movie' | 'tv'): Promise {
+ logger.info('TrailerService', `getTrailerUrl requested: title="${title}", year=${year}, tmdbId=${tmdbId || 'n/a'}, type=${type || 'n/a'}, useLocal=${this.USE_LOCAL_SERVER}`);
if (this.USE_LOCAL_SERVER) {
// Try local server first, fallback to XPrime if it fails
const localResult = await this.getTrailerFromLocalServer(title, year, tmdbId, type);
if (localResult) {
+ logger.info('TrailerService', 'Returning trailer URL from local server');
return localResult;
}
@@ -46,6 +54,7 @@ export class TrailerService {
*/
private static async getTrailerFromLocalServer(title: string, year: number, tmdbId?: string, type?: 'movie' | 'tv'): Promise {
try {
+ const startTime = Date.now();
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.TIMEOUT);
@@ -65,6 +74,8 @@ export class TrailerService {
}
const url = `${this.AUTO_SEARCH_URL}?${params.toString()}`;
+ logger.info('TrailerService', `Local server request URL: ${url}`);
+ logger.info('TrailerService', `Local server timeout set to ${this.TIMEOUT}ms`);
const response = await fetch(url, {
method: 'GET',
@@ -77,25 +88,55 @@ export class TrailerService {
clearTimeout(timeoutId);
+ const elapsed = Date.now() - startTime;
+ const contentType = response.headers.get('content-type') || 'unknown';
+ logger.info('TrailerService', `Local server response: status=${response.status} ok=${response.ok} content-type=${contentType} elapsedMs=${elapsed}`);
+
+ // Read body as text first so we can log it even on non-200s
+ let rawText = '';
+ try {
+ rawText = await response.text();
+ if (rawText) {
+ const preview = rawText.length > 200 ? `${rawText.slice(0, 200)}...` : rawText;
+ logger.info('TrailerService', `Local server body preview: ${preview}`);
+ } else {
+ logger.info('TrailerService', 'Local server body is empty');
+ }
+ } catch (e) {
+ const msg = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
+ logger.warn('TrailerService', `Failed reading local server body text: ${msg}`);
+ }
+
if (!response.ok) {
logger.warn('TrailerService', `Auto-search failed: ${response.status} ${response.statusText}`);
return null;
}
- const data = await response.json();
+ // Attempt to parse JSON from the raw text
+ let data: any = null;
+ try {
+ data = rawText ? JSON.parse(rawText) : null;
+ const keys = typeof data === 'object' && data !== null ? Object.keys(data).join(',') : typeof data;
+ logger.info('TrailerService', `Local server JSON parsed. Keys/Type: ${keys}`);
+ } catch (e) {
+ const msg = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
+ logger.warn('TrailerService', `Failed to parse local server JSON: ${msg}`);
+ return null;
+ }
if (!data.url || !this.isValidTrailerUrl(data.url)) {
logger.warn('TrailerService', `Invalid trailer URL from auto-search: ${data.url}`);
return null;
}
- logger.info('TrailerService', `Successfully found trailer: ${data.url.substring(0, 50)}...`);
+ logger.info('TrailerService', `Successfully found trailer: ${String(data.url).substring(0, 80)}...`);
return data.url;
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
- logger.warn('TrailerService', 'Auto-search request timed out');
+ logger.warn('TrailerService', `Auto-search request timed out after ${this.TIMEOUT}ms`);
} else {
- logger.error('TrailerService', 'Error in auto-search:', error);
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
+ logger.error('TrailerService', `Error in auto-search: ${msg}`);
}
return null; // Return null to trigger XPrime fallback
}
@@ -115,6 +156,8 @@ export class TrailerService {
const url = `${this.XPRIME_URL}?title=${encodeURIComponent(title)}&year=${year}`;
logger.info('TrailerService', `Fetching trailer from XPrime for: ${title} (${year})`);
+ logger.info('TrailerService', `XPrime request URL: ${url}`);
+ logger.info('TrailerService', `XPrime timeout set to ${this.TIMEOUT}ms`);
const response = await fetch(url, {
method: 'GET',
@@ -127,12 +170,14 @@ export class TrailerService {
clearTimeout(timeoutId);
+ logger.info('TrailerService', `XPrime response: status=${response.status} ok=${response.ok}`);
if (!response.ok) {
logger.warn('TrailerService', `XPrime failed: ${response.status} ${response.statusText}`);
return null;
}
const trailerUrl = await response.text();
+ logger.info('TrailerService', `XPrime raw URL length: ${trailerUrl ? trailerUrl.length : 0}`);
if (!trailerUrl || !this.isValidTrailerUrl(trailerUrl.trim())) {
logger.warn('TrailerService', `Invalid trailer URL from XPrime: ${trailerUrl}`);
@@ -145,9 +190,10 @@ export class TrailerService {
return cleanUrl;
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
- logger.warn('TrailerService', 'XPrime request timed out');
+ logger.warn('TrailerService', `XPrime request timed out after ${this.TIMEOUT}ms`);
} else {
- logger.error('TrailerService', 'Error fetching from XPrime:', error);
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
+ logger.error('TrailerService', `Error fetching from XPrime: ${msg}`);
}
return null;
}
@@ -218,16 +264,21 @@ export class TrailerService {
if (url.includes('M3U')) {
// Try to get M3U without encryption first, then with encryption
const baseUrl = url.split('?')[0];
- return `${baseUrl}?formats=M3U+none,M3U+appleHlsEncryption`;
+ const best = `${baseUrl}?formats=M3U+none,M3U+appleHlsEncryption`;
+ logger.info('TrailerService', `Optimized format URL from M3U: ${best.substring(0, 80)}...`);
+ return best;
}
// Fallback to MP4 if available
if (url.includes('MPEG4')) {
const baseUrl = url.split('?')[0];
- return `${baseUrl}?formats=MPEG4`;
+ const best = `${baseUrl}?formats=MPEG4`;
+ logger.info('TrailerService', `Optimized format URL from MPEG4: ${best.substring(0, 80)}...`);
+ return best;
}
}
// Return the original URL if no format optimization is needed
+ logger.info('TrailerService', 'No format optimization applied');
return url;
}
@@ -238,7 +289,9 @@ export class TrailerService {
* @returns Promise - True if trailer is available
*/
static async isTrailerAvailable(title: string, year: number): Promise {
+ logger.info('TrailerService', `Checking trailer availability for: ${title} (${year})`);
const trailerUrl = await this.getTrailerUrl(title, year);
+ logger.info('TrailerService', `Trailer availability for ${title} (${year}): ${trailerUrl ? 'available' : 'not available'}`);
return trailerUrl !== null;
}
@@ -249,9 +302,11 @@ export class TrailerService {
* @returns Promise - Trailer data or null if not found
*/
static async getTrailerData(title: string, year: number): Promise {
+ logger.info('TrailerService', `getTrailerData for: ${title} (${year})`);
const url = await this.getTrailerUrl(title, year);
if (!url) {
+ logger.info('TrailerService', 'No trailer URL found for getTrailerData');
return null;
}
@@ -262,6 +317,65 @@ export class TrailerService {
};
}
+ /**
+ * Fetches trailer directly from a known YouTube URL
+ * @param youtubeUrl - The YouTube URL to process
+ * @param title - Optional title for logging/caching
+ * @param year - Optional year for logging/caching
+ * @returns Promise - The direct streaming URL or null if failed
+ */
+ static async getTrailerFromYouTubeUrl(youtubeUrl: string, title?: string, year?: string): Promise {
+ try {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), this.TIMEOUT);
+
+ const params = new URLSearchParams();
+ params.append('youtube_url', youtubeUrl);
+ if (title) params.append('title', title);
+ if (year) params.append('year', year.toString());
+
+ const url = `${this.ENV_LOCAL_BASE}${this.ENV_LOCAL_TRAILER_PATH}?${params.toString()}`;
+ logger.info('TrailerService', `Fetching trailer directly from YouTube URL: ${youtubeUrl}`);
+ logger.info('TrailerService', `Direct trailer request URL: ${url}`);
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ 'User-Agent': 'Nuvio/1.0',
+ },
+ signal: controller.signal,
+ });
+
+ clearTimeout(timeoutId);
+
+ logger.info('TrailerService', `Direct trailer response: status=${response.status} ok=${response.ok}`);
+
+ if (!response.ok) {
+ logger.warn('TrailerService', `Direct trailer failed: ${response.status} ${response.statusText}`);
+ return null;
+ }
+
+ const data = await response.json();
+
+ if (!data.url || !this.isValidTrailerUrl(data.url)) {
+ logger.warn('TrailerService', `Invalid trailer URL from direct fetch: ${data.url}`);
+ return null;
+ }
+
+ logger.info('TrailerService', `Successfully got direct trailer: ${String(data.url).substring(0, 80)}...`);
+ return data.url;
+ } catch (error) {
+ if (error instanceof Error && error.name === 'AbortError') {
+ logger.warn('TrailerService', `Direct trailer request timed out after ${this.TIMEOUT}ms`);
+ } else {
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
+ logger.error('TrailerService', `Error in direct trailer fetch: ${msg}`);
+ }
+ return null;
+ }
+ }
+
/**
* Switch between local server and XPrime API
* @param useLocal - true for local server, false for XPrime
@@ -292,6 +406,7 @@ export class TrailerService {
localServer: { status: 'online' | 'offline'; responseTime?: number };
xprimeServer: { status: 'online' | 'offline'; responseTime?: number };
}> {
+ logger.info('TrailerService', 'Testing servers (local and XPrime)');
const results: {
localServer: { status: 'online' | 'offline'; responseTime?: number };
xprimeServer: { status: 'online' | 'offline'; responseTime?: number };
@@ -312,9 +427,11 @@ export class TrailerService {
status: 'online',
responseTime: Date.now() - startTime
};
+ logger.info('TrailerService', `Local server online. Response time: ${results.localServer.responseTime}ms`);
}
} catch (error) {
- logger.warn('TrailerService', 'Local server test failed:', error);
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
+ logger.warn('TrailerService', `Local server test failed: ${msg}`);
}
// Test XPrime server
@@ -329,11 +446,14 @@ export class TrailerService {
status: 'online',
responseTime: Date.now() - startTime
};
+ logger.info('TrailerService', `XPrime server online. Response time: ${results.xprimeServer.responseTime}ms`);
}
} catch (error) {
- logger.warn('TrailerService', 'XPrime server test failed:', error);
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
+ logger.warn('TrailerService', `XPrime server test failed: ${msg}`);
}
+ logger.info('TrailerService', `Server test results -> local: ${results.localServer.status}, xprime: ${results.xprimeServer.status}`);
return results;
}
}
diff --git a/src/types/metadata.ts b/src/types/metadata.ts
index de2338a3..be8bc396 100644
--- a/src/types/metadata.ts
+++ b/src/types/metadata.ts
@@ -1,6 +1,9 @@
import { TMDBEpisode } from '../services/tmdbService';
import { StreamingContent } from '../services/catalogService';
+// Re-export StreamingContent for convenience
+export { StreamingContent };
+
// Types for route params
export type RouteParams = {
id: string;