From a7aacb4a73378ee7fa650f129603ef8170f9aadc Mon Sep 17 00:00:00 2001 From: Joe Milham Date: Thu, 17 Oct 2024 19:23:19 -0300 Subject: [PATCH 1/3] Android - modernize loadPlaylist method with new types --- .../jwplayer/rnjwplayer/RNJWPlayerModule.java | 39 +++++++++++++++++++ .../java/com/jwplayer/rnjwplayer/Util.java | 33 ++++++++++++---- index.d.ts | 2 +- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java index aea3db7..9a54ece 100644 --- a/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +++ b/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java @@ -82,6 +82,45 @@ public void execute (NativeViewHierarchyManager nvhm) { } } + @ReactMethod + public void loadPlaylist(final int reactTag, final String playlistUrl) { + try { + UIManagerModule uiManager = mReactContext.getNativeModule(UIManagerModule.class); + uiManager.addUIBlock(new UIBlock() { + public void execute (NativeViewHierarchyManager nvhm) { + RNJWPlayerView playerView = (RNJWPlayerView) nvhm.resolveView(reactTag); + + if (playerView != null && playerView.mPlayerView != null) { + JWPlayer player = playerView.mPlayerView.getPlayer(); + + PlayerConfig oldConfig = player.getConfig(); + PlayerConfig config = new PlayerConfig.Builder() + .autostart(oldConfig.getAutostart()) + .nextUpOffset(oldConfig.getNextUpOffset()) + .repeat(oldConfig.getRepeat()) + .relatedConfig(oldConfig.getRelatedConfig()) + .displayDescription(oldConfig.getDisplayDescription()) + .displayTitle(oldConfig.getDisplayTitle()) + .advertisingConfig(oldConfig.getAdvertisingConfig()) + .stretching(oldConfig.getStretching()) + .uiConfig(oldConfig.getUiConfig()) + .playlistUrl(playlistUrl) + .allowCrossProtocolRedirects(oldConfig.getAllowCrossProtocolRedirects()) + .preload(oldConfig.getPreload()) + .useTextureView(oldConfig.useTextureView()) + .thumbnailPreview(oldConfig.getThumbnailPreview()) + .mute(oldConfig.getMute()) + .build(); + + player.setup(config); + } + } + }); + } catch (IllegalViewOperationException e) { + throw e; + } + } + @ReactMethod public void play(final int reactTag) { try { diff --git a/android/src/main/java/com/jwplayer/rnjwplayer/Util.java b/android/src/main/java/com/jwplayer/rnjwplayer/Util.java index 44becfc..3e96c1d 100644 --- a/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +++ b/android/src/main/java/com/jwplayer/rnjwplayer/Util.java @@ -2,17 +2,21 @@ import static androidx.media3.common.util.Util.toByteArray; +import android.util.Log; import android.util.Patterns; import android.webkit.URLUtil; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.jwplayer.pub.api.JsonHelper; import com.jwplayer.pub.api.media.ads.AdBreak; import com.jwplayer.pub.api.media.captions.Caption; import com.jwplayer.pub.api.media.captions.CaptionType; import com.jwplayer.pub.api.media.playlists.MediaSource; import com.jwplayer.pub.api.media.playlists.PlaylistItem; +import org.json.JSONObject; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -20,8 +24,8 @@ import java.net.URL; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Locale; +import java.util.Map; public class Util { @@ -62,7 +66,7 @@ public static byte[] executePost(String url, byte[] data, Map re } } - public static boolean isValidURL(String url){ + public static boolean isValidURL(String url) { return URLUtil.isValidUrl(url) && Patterns.WEB_URL.matcher(url).matches(); } @@ -75,14 +79,28 @@ public static List createPlaylist(ReadableArray playlistItems) { while (playlistItems.size() > j) { ReadableMap playlistItem = playlistItems.getMap(j); - PlaylistItem newPlayListItem = getPlaylistItem((playlistItem)); - playlist.add(newPlayListItem); + JSONObject obj; + PlaylistItem item = null; + // Try since legacy config may or may not conform to this standard + try { + obj = MapUtil.toJSONObject(playlistItem); + item = JsonHelper.parsePlaylistItemJson(obj); + } catch (Exception ex) { + Log.e("createPlaylist", ex.toString()); + } + if (item != null) { + playlist.add(item); + } else { + // Try to use the legacy format + PlaylistItem newPlayListItem = getPlaylistItem((playlistItem)); + playlist.add(newPlayListItem); + } j++; } return playlist; } - public static PlaylistItem getPlaylistItem (ReadableMap playlistItem) { + public static PlaylistItem getPlaylistItem(ReadableMap playlistItem) { PlaylistItem.Builder itemBuilder = new PlaylistItem.Builder(); if (playlistItem.hasKey("file")) { @@ -194,11 +212,12 @@ public static PlaylistItem getPlaylistItem (ReadableMap playlistItem) { /** * Internal helper for parsing a caption type from a known string + * * @param type one of "CAPTIONS", "CHAPTERS", "THUMBNAILS" * @return the correct Enum CaptionType */ - public static CaptionType getCaptionType(String type){ - for (CaptionType captionType: CaptionType.values()) { + public static CaptionType getCaptionType(String type) { + for (CaptionType captionType : CaptionType.values()) { if (captionType.name().equals(type)) { return CaptionType.valueOf(type); } diff --git a/index.d.ts b/index.d.ts index 390c92a..86578c2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -564,7 +564,7 @@ declare module "@jwplayer/jwplayer-react-native" { setControls(show: boolean): void; setLockScreenControls(show: boolean): void; seekTo(time: number): void; - loadPlaylist(playlistItems: PlaylistItem[]): void; + loadPlaylist(playlistItems: PlaylistItem[] | JwPlaylistItem[] | string): void; setFullscreen(fullScreen: boolean): void; position(): Promise; setUpCastController(): void; From ea893983d3b7e9a58d59add83215f2926a57a2a1 Mon Sep 17 00:00:00 2001 From: Joe Milham Date: Fri, 18 Oct 2024 11:46:21 -0300 Subject: [PATCH 2/3] Add todo for iOS --- ios/RNJWPlayer/RNJWPlayerViewManager.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/RNJWPlayer/RNJWPlayerViewManager.swift b/ios/RNJWPlayer/RNJWPlayerViewManager.swift index a8f6107..4db74b2 100644 --- a/ios/RNJWPlayer/RNJWPlayerViewManager.swift +++ b/ios/RNJWPlayer/RNJWPlayerViewManager.swift @@ -467,6 +467,8 @@ class RNJWPlayerViewManager: RCTViewManager { var playlistArray = [JWPlayerItem]() for item in playlist { + // TODO Update this to better parse JWP Playlist Items: + // awaiting JWP SDK exposure of JWJSONParser.playlist if let playerItem = try? view.getPlayerItem(item: item as! [String: Any]) { playlistArray.append(playerItem) } From 2f5cba97acda54b18e29d86b3fd7beeb74e78eec Mon Sep 17 00:00:00 2001 From: Joe Milham Date: Fri, 18 Oct 2024 12:30:00 -0300 Subject: [PATCH 3/3] Allow for handling of playlist url in loadplaylist for iOS --- ios/RNJWPlayer/RNJWPlayerViewManager.m | 2 ++ ios/RNJWPlayer/RNJWPlayerViewManager.swift | 33 ++++++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/ios/RNJWPlayer/RNJWPlayerViewManager.m b/ios/RNJWPlayer/RNJWPlayerViewManager.m index c47d6d5..126eeaa 100644 --- a/ios/RNJWPlayer/RNJWPlayerViewManager.m +++ b/ios/RNJWPlayer/RNJWPlayerViewManager.m @@ -131,6 +131,8 @@ @interface RCT_EXTERN_MODULE(RNJWPlayerViewManager, RCTViewManager) RCT_EXTERN_METHOD(loadPlaylist: (nonnull NSNumber *)reactTag: (nonnull NSArray *)playlist) +RCT_EXTERN_METHOD(loadPlaylist: (nonnull NSNumber *)reactTag: (nonnull NSString *)playlist) + RCT_EXTERN_METHOD(setFullscreen: (nonnull NSNumber *)reactTag: (BOOL)fullscreen) @end diff --git a/ios/RNJWPlayer/RNJWPlayerViewManager.swift b/ios/RNJWPlayer/RNJWPlayerViewManager.swift index 4db74b2..8406693 100644 --- a/ios/RNJWPlayer/RNJWPlayerViewManager.swift +++ b/ios/RNJWPlayer/RNJWPlayerViewManager.swift @@ -457,7 +457,7 @@ class RNJWPlayerViewManager: RCTViewManager { } } - @objc func loadPlaylist(_ reactTag: NSNumber, _ playlist: [Any]) { + @objc func loadPlaylist(_ reactTag: NSNumber, _ playlist: Any) { self.bridge.uiManager.addUIBlock { uiManager, viewRegistry in guard let view = viewRegistry?[reactTag] as? RNJWPlayerView else { print("Invalid view returned from registry, expecting RNJWPlayerView, got: \(String(describing: viewRegistry?[reactTag]))") @@ -466,19 +466,28 @@ class RNJWPlayerViewManager: RCTViewManager { var playlistArray = [JWPlayerItem]() - for item in playlist { - // TODO Update this to better parse JWP Playlist Items: - // awaiting JWP SDK exposure of JWJSONParser.playlist - if let playerItem = try? view.getPlayerItem(item: item as! [String: Any]) { - playlistArray.append(playerItem) + if playlist is NSArray { + for item in playlist as! [Any] { + // TODO Update this to better parse JWP Playlist Items: + // awaiting JWP SDK exposure of JWJSONParser.playlist + if let playerItem = try? view.getPlayerItem(item: item as! [String: Any]) { + playlistArray.append(playerItem) + } + } + + if let playerView = view.playerView { + playerView.player.loadPlaylist(items: playlistArray) + } else if let playerViewController = view.playerViewController { + playerViewController.player.loadPlaylist(items: playlistArray) + } + } else { + if let playerView = view.playerView { + playerView.player.loadPlaylist(url: URL(string: playlist as! String)!) + } else if let playerViewController = view.playerViewController { + playerViewController.player.loadPlaylist(url: URL(string: playlist as! String)!) } } - - if let playerView = view.playerView { - playerView.player.loadPlaylist(items: playlistArray) - } else if let playerViewController = view.playerViewController { - playerViewController.player.loadPlaylist(items: playlistArray) - } + } }