From f64d34d3ccd846f3903a9bf28acfd69c836ed863 Mon Sep 17 00:00:00 2001 From: Syed Ibrahim Date: Tue, 17 Jun 2025 21:07:42 +0530 Subject: [PATCH 1/2] feat: expose player events in ReactNative --- android/build.gradle | 2 +- .../com/tpstreams/TPStreamsDownloadModule.kt | 105 ++++++++++++++++++ .../java/com/tpstreams/TPStreamsRNPackage.kt | 1 + src/TPStreamsDownload.tsx | 40 +++++++ src/index.tsx | 3 + 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 android/src/main/java/com/tpstreams/TPStreamsDownloadModule.kt create mode 100644 src/TPStreamsDownload.tsx diff --git a/android/build.gradle b/android/build.gradle index 1942b19..5745479 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -84,7 +84,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "com.tpstreams:tpstreams-player:0.0.6" + implementation "com.tpstreams:tpstreams-player:0.0.8" } react { diff --git a/android/src/main/java/com/tpstreams/TPStreamsDownloadModule.kt b/android/src/main/java/com/tpstreams/TPStreamsDownloadModule.kt new file mode 100644 index 0000000..5888489 --- /dev/null +++ b/android/src/main/java/com/tpstreams/TPStreamsDownloadModule.kt @@ -0,0 +1,105 @@ +package com.tpstreams + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.WritableMap +import com.facebook.react.bridge.WritableArray +import com.facebook.react.bridge.Arguments +import com.tpstreams.player.download.DownloadTracker + +class TPStreamsDownloadModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private val downloadTracker: DownloadTracker by lazy { + try { + DownloadTracker.getInstance(reactApplicationContext) + } catch (e: Exception) { + throw RuntimeException("Failed to initialize DownloadTracker. Make sure TPStreams library is properly initialized.", e) + } + } + + override fun getName(): String { + return "TPStreamsDownload" + } + + @ReactMethod + fun getDownloads(promise: Promise) { + try { + val downloadItems = downloadTracker.getAllDownloadItems() + val result = Arguments.createArray() + + downloadItems.forEach { item -> + val itemMap = Arguments.createMap() + + itemMap.putString("videoId", item.assetId) + itemMap.putString("title", item.title) + + item.thumbnailUrl?.let { thumbnailUrl -> + itemMap.putString("thumbnailUrl", thumbnailUrl) + } + + itemMap.putDouble("totalBytes", item.totalBytes.toDouble()) + itemMap.putDouble("downloadedBytes", item.downloadedBytes.toDouble()) + itemMap.putDouble("progressPercentage", item.progressPercentage.toDouble()) + itemMap.putInt("state", item.state) + + result.pushMap(itemMap) + } + + promise.resolve(result) + } catch (e: Exception) { + promise.reject("GET_DOWNLOADS_ERROR", "Failed to get downloads: ${e.message}", e) + } + } + + @ReactMethod + fun getDownloadStatus(videoId: String, promise: Promise) { + try { + val status = downloadTracker.getDownloadStatus(videoId) + promise.resolve(status) + } catch (e: Exception) { + promise.reject("GET_STATUS_ERROR", "Failed to get download status for video $videoId: ${e.message}", e) + } + } + + @ReactMethod + fun pauseDownload(videoId: String, promise: Promise) { + try { + val success = downloadTracker.pauseDownload(videoId) + promise.resolve(success) + } catch (e: Exception) { + promise.reject("PAUSE_DOWNLOAD_ERROR", "Failed to pause download for video $videoId: ${e.message}", e) + } + } + + @ReactMethod + fun resumeDownload(videoId: String, promise: Promise) { + try { + val success = downloadTracker.resumeDownload(videoId) + promise.resolve(success) + } catch (e: Exception) { + promise.reject("RESUME_DOWNLOAD_ERROR", "Failed to resume download for video $videoId: ${e.message}", e) + } + } + + @ReactMethod + fun cancelDownload(videoId: String, promise: Promise) { + try { + val success = downloadTracker.removeDownload(videoId) + promise.resolve(success) + } catch (e: Exception) { + promise.reject("CANCEL_DOWNLOAD_ERROR", "Failed to cancel download for video $videoId: ${e.message}", e) + } + } + + @ReactMethod + fun isDownloaded(videoId: String, promise: Promise) { + try { + val downloaded = downloadTracker.isDownloaded(videoId) + promise.resolve(downloaded) + } catch (e: Exception) { + promise.reject("IS_DOWNLOADED_ERROR", "Failed to check download status for video $videoId: ${e.message}", e) + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/tpstreams/TPStreamsRNPackage.kt b/android/src/main/java/com/tpstreams/TPStreamsRNPackage.kt index 5e748f2..35ef63a 100644 --- a/android/src/main/java/com/tpstreams/TPStreamsRNPackage.kt +++ b/android/src/main/java/com/tpstreams/TPStreamsRNPackage.kt @@ -16,6 +16,7 @@ class TPStreamsRNPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List { val modules: MutableList = ArrayList() modules.add(TPStreamsRNModule(reactContext)) + modules.add(TPStreamsDownloadModule(reactContext)) return modules } } diff --git a/src/TPStreamsDownload.tsx b/src/TPStreamsDownload.tsx new file mode 100644 index 0000000..c0a2822 --- /dev/null +++ b/src/TPStreamsDownload.tsx @@ -0,0 +1,40 @@ +import { NativeModules } from 'react-native'; + +const { TPStreamsDownload } = NativeModules; + +export interface DownloadItem { + videoId: string; + assetId: string; + title: string; + thumbnailUrl?: string; + totalBytes: number; + downloadedBytes: number; + progressPercentage: number; + state: number; +} + +export default { + getDownloads(): Promise { + return TPStreamsDownload.getDownloads(); + }, + + getDownloadStatus(videoId: string): Promise { + return TPStreamsDownload.getDownloadStatus(videoId); + }, + + pauseDownload(videoId: string): Promise { + return TPStreamsDownload.pauseDownload(videoId); + }, + + resumeDownload(videoId: string): Promise { + return TPStreamsDownload.resumeDownload(videoId); + }, + + cancelDownload(videoId: string): Promise { + return TPStreamsDownload.cancelDownload(videoId); + }, + + isDownloaded(videoId: string): Promise { + return TPStreamsDownload.isDownloaded(videoId); + }, +}; diff --git a/src/index.tsx b/src/index.tsx index af74864..b1e5b9c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,6 +7,9 @@ export * from './TPStreamsPlayerViewNativeComponent'; export { default as TPStreamsPlayerView } from './TPStreamsPlayer'; export type { TPStreamsPlayerRef } from './TPStreamsPlayer'; +export { default as TPStreamsDownload } from './TPStreamsDownload'; +export type { DownloadItem } from './TPStreamsDownload'; + const TPStreamsModule = NativeModules.TPStreams; export const TPStreams = { From ee0a32b370bcc2c9e5d9315b955e6038ba8502a4 Mon Sep 17 00:00:00 2001 From: Syed Ibrahim Date: Tue, 17 Jun 2025 21:20:27 +0530 Subject: [PATCH 2/2] fix: remove non-existing data item --- src/TPStreamsDownload.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TPStreamsDownload.tsx b/src/TPStreamsDownload.tsx index c0a2822..536f570 100644 --- a/src/TPStreamsDownload.tsx +++ b/src/TPStreamsDownload.tsx @@ -4,7 +4,6 @@ const { TPStreamsDownload } = NativeModules; export interface DownloadItem { videoId: string; - assetId: string; title: string; thumbnailUrl?: string; totalBytes: number;