Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update React Native to 0.76.2 #2395

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

puckey
Copy link
Collaborator

@puckey puckey commented Nov 7, 2024

@puckey puckey requested a review from dcvz as a code owner November 7, 2024 13:23
@lovegaoshi
Copy link
Contributor

pls note #2370 breaks on rn <0.76.1

@smfunder
Copy link

I came here to see what would be the progress for this PR to be merged? Would it fully work with RN 0.76.1 is there any help I can provide to try it out?

@puckey puckey changed the title Update React Native to 0.76.1 Update React Native to 0.76.2 Nov 18, 2024
@puckey
Copy link
Collaborator Author

puckey commented Nov 18, 2024

I updated the example app to 0.76.2, which should have fixed the remaining timer issues through facebook/react-native@ee7b4e2. @smfunder would you like to verify?

@smfunder
Copy link

@puckey what would be the best way to try it out? Should I clone the library on this PR's branch and then replace my node_modules/react-native-track-player folder with the content of it?

@lovegaoshi
Copy link
Contributor

u should clone and start testing the example app.

if ur absolutely sure to test in ur own app, do note newarch breaks/bugs many libs right now, so if it doesnt work u shouldnt comment on this PR but the respective libs.

u should first make sure ur project uses RN 0.76.2. then for RNTP instead of a version, use this PR's SHA. for example https://github.com/lovegaoshi/azusa-player-mobile/blob/e3ce4f61806075ce5d6458748b570e9733c7fc2a/package.json#L113. but use this PR's SHA instead

@smfunder
Copy link

thank you @lovegaoshi I will try it asap and get back to you here!

@mrevanzak
Copy link

typescript keep yelling if i use this branch. any idea why? but its work tho

@puckey
Copy link
Collaborator Author

puckey commented Nov 28, 2024

typescript keep yelling if i use this branch. any idea why? but its work tho

What error are you seeing?

@mrevanzak
Copy link

typescript keep yelling if i use this branch. any idea why? but its work tho

What error are you seeing?

image

@tarkanlar
Copy link

typescript keep yelling if i use this branch. any idea why? but its work tho

I figured that out. Lib is not being downloaded in this branch. so I copy lib from latest react native and paste into node_modules/react-native-track-player folder

@yagudaev
Copy link

yagudaev commented Dec 7, 2024

I too had issues with typescript following this advice: #2389 (comment)

There is no lib/src directory just lib in my case. Two more things

  1. I am in a mono repo using Yarn
  2. I ran yarn build in the directory and it failed, then ran npm build and it failed as well.

CleanShot 2024-12-07 at 00 14 49@2x

Hope this helps, love to see this merged and the whole thing sorted out

@mrevanzak
Copy link

hope this help. use this patch

diff --git a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
index b2409a09939164c49c0f7a16bb6d3284e8eab8fb..83228b20d174ac4842ed2707263cb4bd6b7c10a0 100644
--- a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
+++ b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
@@ -49,7 +49,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     override fun onServiceConnected(name: ComponentName, service: IBinder) {
-        scope.launch {
+        launchInScope {
             // If a binder already exists, don't get a new one
             if (!::musicService.isInitialized) {
                 val binder: MusicService.MusicBinder = service as MusicService.MusicBinder
@@ -66,7 +66,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
      * Called when a connection to the Service has been lost.
      */
     override fun onServiceDisconnected(name: ComponentName) {
-        scope.launch {
+        launchInScope {
             isServiceBound = false
         }
     }
@@ -251,8 +251,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun updateOptions(data: ReadableMap?, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun updateOptions(data: ReadableMap?, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         val options = Arguments.toBundle(data)
 
@@ -264,14 +264,14 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         try {
             val tracks = readableArrayToTrackList(data);
             if (insertBeforeIndex < -1 || insertBeforeIndex > musicService.tracks.size) {
                 callback.reject("index_out_of_bounds", "The track index is out of bounds")
-                return@launch
+                return@launchInScope
             }
             val index = if (insertBeforeIndex == -1) musicService.tracks.size else insertBeforeIndex
             musicService.add(
@@ -285,11 +285,11 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun load(data: ReadableMap?, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun load(data: ReadableMap?, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         if (data == null) {
             callback.resolve(null)
-            return@launch
+            return@launchInScope
         }
         val bundle = Arguments.toBundle(data);
         if (bundle is Bundle) {
@@ -301,15 +301,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun move(fromIndex: Int, toIndex: Int, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun move(fromIndex: Int, toIndex: Int, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         musicService.move(fromIndex, toIndex)
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun remove(data: ReadableArray?, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun remove(data: ReadableArray?, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         val inputIndexes = Arguments.toList(data)
         if (inputIndexes != null) {
             val size = musicService.tracks.size
@@ -321,7 +321,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
                         "index_out_of_bounds",
                         "One or more indexes was out of bounds"
                     )
-                    return@launch
+                    return@launchInScope
                 }
                 indexes.add(index)
             }
@@ -332,8 +332,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
 
     @ReactMethod
     fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) =
-        scope.launch {
-            if (verifyServiceBoundOrReject(callback)) return@launch
+        launchInScope {
+            if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
             if (index < 0 || index >= musicService.tracks.size) {
                 callback.reject("index_out_of_bounds", "The index is out of bounds")
@@ -348,8 +348,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
         }
 
     @ReactMethod
-    fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         if (musicService.tracks.isEmpty())
             callback.reject("no_current_item", "There is no current item in the player")
@@ -364,8 +364,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun clearNowPlayingMetadata(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun clearNowPlayingMetadata(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         if (musicService.tracks.isEmpty())
             callback.reject("no_current_item", "There is no current item in the player")
@@ -375,16 +375,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun removeUpcomingTracks(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun removeUpcomingTracks(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.removeUpcomingTracks()
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun skip(index: Int, initialTime: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun skip(index: Int, initialTime: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.skip(index)
 
@@ -396,8 +396,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun skipToNext(initialTime: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun skipToNext(initialTime: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.skipToNext()
 
@@ -409,8 +409,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun skipToPrevious(initialTime: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun skipToPrevious(initialTime: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.skipToPrevious()
 
@@ -422,8 +422,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun reset(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun reset(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.stop()
         delay(300) // Allow playback to stop
@@ -433,116 +433,116 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun play(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun play(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.play()
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun pause(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun pause(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.pause()
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun stop(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun stop(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.stop()
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun seekTo(seconds: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun seekTo(seconds: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.seekTo(seconds)
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun seekBy(offset: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun seekBy(offset: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.seekBy(offset)
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun retry(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun retry(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.retry()
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun setVolume(volume: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun setVolume(volume: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.setVolume(volume)
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun getVolume(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getVolume(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getVolume())
     }
 
     @ReactMethod
-    fun setRate(rate: Float, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun setRate(rate: Float, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.setRate(rate)
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun getRate(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getRate(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getRate())
     }
 
     @ReactMethod
-    fun setRepeatMode(mode: Int, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun setRepeatMode(mode: Int, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.setRepeatMode(RepeatMode.fromOrdinal(mode))
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun getRepeatMode(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getRepeatMode(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getRepeatMode().ordinal)
     }
 
     @ReactMethod
-    fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         musicService.playWhenReady = playWhenReady
         callback.resolve(null)
     }
 
     @ReactMethod
-    fun getPlayWhenReady(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getPlayWhenReady(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.playWhenReady)
     }
 
     @ReactMethod
-    fun getTrack(index: Int, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getTrack(index: Int, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         if (index >= 0 && index < musicService.tracks.size) {
             callback.resolve(Arguments.fromBundle(musicService.tracks[index].originalItem))
@@ -552,15 +552,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun getQueue(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getQueue(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(Arguments.fromList(musicService.tracks.map { it.originalItem }))
     }
 
     @ReactMethod
-    fun setQueue(data: ReadableArray?, callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun setQueue(data: ReadableArray?, callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         try {
             musicService.clear()
@@ -572,16 +572,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun getActiveTrackIndex(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getActiveTrackIndex(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         callback.resolve(
             if (musicService.tracks.isEmpty()) null else musicService.getCurrentTrackIndex()
         )
     }
 
     @ReactMethod
-    fun getActiveTrack(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getActiveTrack(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         callback.resolve(
             if (musicService.tracks.isEmpty()) null
             else Arguments.fromBundle(
@@ -591,29 +591,29 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun getDuration(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getDuration(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getDurationInSeconds())
     }
 
     @ReactMethod
-    fun getBufferedPosition(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getBufferedPosition(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getBufferedPositionInSeconds())
     }
 
     @ReactMethod
-    fun getPosition(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getPosition(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
 
         callback.resolve(musicService.getPositionInSeconds())
     }
 
     @ReactMethod
-    fun getProgress(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getProgress(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         var bundle = Bundle()
         bundle.putDouble("duration", musicService.getDurationInSeconds());
         bundle.putDouble("position", musicService.getPositionInSeconds());
@@ -622,8 +622,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
     }
 
     @ReactMethod
-    fun getPlaybackState(callback: Promise) = scope.launch {
-        if (verifyServiceBoundOrReject(callback)) return@launch
+    fun getPlaybackState(callback: Promise) = launchInScope {
+        if (verifyServiceBoundOrReject(callback)) return@launchInScope
         callback.resolve(Arguments.fromBundle(musicService.getPlayerStateBundle(musicService.state)))
     }
+
+    // Bridgeless interop layer tries to pass the `Job` from `scope.launch` to the JS side
+    // which causes an exception. We can work around this using a wrapper.
+    private fun launchInScope(block: suspend () -> Unit) {
+        scope.launch {
+            block()
+        }
+    }
 }
diff --git a/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt b/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
index 9d6d869efcece065618d4f2cefdc8c54831af9ed..d1dc43f731fe6166cfc4687da0db84da2a50e89b 100644
--- a/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
+++ b/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
@@ -741,9 +741,7 @@ class MusicService : HeadlessJsTaskService() {
 
     @MainThread
     private fun emit(event: String, data: Bundle? = null) {
-        reactNativeHost.reactInstanceManager.currentReactContext
-            ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
-            ?.emit(event, data?.let { Arguments.fromBundle(it) })
+        reactContext.emitDeviceEvent(event, data?.let { Arguments.fromBundle(it) })
     }
 
     @MainThread
@@ -751,9 +749,7 @@ class MusicService : HeadlessJsTaskService() {
         val payload = Arguments.createArray()
         data.forEach { payload.pushMap(Arguments.fromBundle(it)) }
 
-        reactNativeHost.reactInstanceManager.currentReactContext
-            ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
-            ?.emit(event, payload)
+        reactContext.emitDeviceEvent(event, payload)
     }
 
     override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig {
diff --git a/ios/RNTrackPlayer/RNTrackPlayerBridge.m b/ios/RNTrackPlayer/RNTrackPlayerBridge.m
index 7741994191921ed86f7577f7ce589b3939d9dd49..776c09ec0ae450daa4dc9031ccd3ff4baba016d3 100644
--- a/ios/RNTrackPlayer/RNTrackPlayerBridge.m
+++ b/ios/RNTrackPlayer/RNTrackPlayerBridge.m
@@ -151,17 +151,4 @@ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject)
                   resolver:(RCTPromiseResolveBlock)resolve
                   rejecter:(RCTPromiseRejectBlock)reject);
 
-RCT_EXTERN_METHOD(getSleepTimerProgress:(RCTPromiseResolveBlock)resolve
-              rejecter:(RCTPromiseRejectBlock)reject);
-
-RCT_EXTERN_METHOD(setSleepTimer:(double)time
-                  resolver:(RCTPromiseResolveBlock)resolve
-                  rejecter:(RCTPromiseRejectBlock)reject);
-
-RCT_EXTERN_METHOD(sleepWhenActiveTrackReachesEnd:(RCTPromiseResolveBlock)resolve
-                  rejecter:(RCTPromiseRejectBlock)reject);
-
-RCT_EXTERN_METHOD(clearSleepTimer:(RCTPromiseResolveBlock)resolve
-              rejecter:(RCTPromiseRejectBlock)reject);
-
 @end

@afkcodes
Copy link

Hello @puckey @lovegaoshi Please let me know how i can help in testing and getting this merged asap.

@lovegaoshi
Copy link
Contributor

buddy its oss and mit. fork it, patch it, and use it urself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants