From 83dc639302c28d8dbb01065c16ba0e914039f029 Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Mon, 18 Nov 2024 21:58:45 +0200 Subject: [PATCH 1/6] [CORE-5162] Implementation for Bitmovin analytics --- Sources/PlaybackSDK/PlayBackSDKManager.swift | 5 ++++- .../BitMovinPlugin/BitMovinPlayerView.swift | 5 ++++- .../BitMovinPlugin/BitmovinPlayerPlugin.swift | 16 ++++++++++++++-- .../Player Plugin/VideoPlayerPlugin.swift | 2 +- .../PlayerUIView/PlaybackUIView.swift | 8 ++++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Sources/PlaybackSDK/PlayBackSDKManager.swift b/Sources/PlaybackSDK/PlayBackSDKManager.swift index 43cf317..666b928 100644 --- a/Sources/PlaybackSDK/PlayBackSDKManager.swift +++ b/Sources/PlaybackSDK/PlayBackSDKManager.swift @@ -139,17 +139,19 @@ public class PlayBackSDKManager { - Parameters: - entryID: The unique identifier of the video entry to be loaded. - authorizationToken: The token used for authorization to access the video content. + - userId: User identifier to be tracked in analytics - Returns: A view representing the video player configured with the provided entry ID and authorization token. Example usage: ```swift - let playerView = loadPlayer(entryID: "exampleEntryID", authorizationToken: "exampleToken") + let playerView = loadPlayer(entryID: "exampleEntryID", authorizationToken: "exampleToken", userId: "1234abcd") */ public func loadPlayer( entryID: String, authorizationToken: String? = nil, mediaTitle: String? = nil, + userId: String? = nil, onError: ((PlayBackAPIError) -> Void)? ) -> some View { @@ -157,6 +159,7 @@ public class PlayBackSDKManager { entryId: entryID, authorizationToken: authorizationToken, mediaTitle: mediaTitle, + userId: userId, onError: onError ) .id(entryID) diff --git a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift index 2d11fa6..42e0231 100644 --- a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift +++ b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift @@ -58,11 +58,14 @@ public struct BitMovinPlayerView: View { public init(hlsURLString: String, playerConfig: PlayerConfig, title: String) { self.hlsURLString = hlsURLString - let uiConfig = BitmovinUserInterfaceConfig() uiConfig.hideFirstFrame = true playerConfig.styleConfig.userInterfaceConfig = uiConfig + let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK") + + let analytics: BitmovinPlayerAnalytics.AnalyticsPlayerConfig + // Create player based on player and analytics configurations self.player = PlayerFactory.createPlayer( playerConfig: playerConfig diff --git a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift index 4a89aec..910f627 100644 --- a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift @@ -39,11 +39,23 @@ public class BitmovinPlayerPlugin: VideoPlayerPlugin { playerConfig.styleConfig.userInterfaceConfig = uiConfig } - public func playerView(hlsURLString: String, title: String = "") -> AnyView { + private func createAnalyticsConfig(userId: String? = nil) -> AnalyticsPlayerConfig { + guard let licenseKey = PlayBackSDKManager.shared.bitmovinLicense else { + return .disabled + } + let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK", customUserId: userId) + let analytics: BitmovinPlayerAnalytics.AnalyticsPlayerConfig = licenseKey != nil + ? .enabled(analyticsConfig: AnalyticsConfig(licenseKey: licenseKey), defaultMetadata: defaultMetadata) + : .disabled + return analytics + } + + public func playerView(hlsURLString: String, title: String = "", userId: String? = nil) -> AnyView { // Create player based on player and analytics configurations let player = PlayerFactory.createPlayer( - playerConfig: playerConfig + playerConfig: playerConfig, + analytics: self.createAnalyticsConfig(userId: userId) ) self.player = player diff --git a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift index aee1388..e8accd2 100644 --- a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift @@ -19,7 +19,7 @@ public protocol VideoPlayerPlugin: AnyObject { // TODO: add event /// func handleEvent(event: BitmovinPlayerCore.PlayerEvent) - func playerView(hlsURLString: String, title: String) -> AnyView + func playerView(hlsURLString: String, title: String, userId: String?) -> AnyView func play() diff --git a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift index fe5f2d1..9fef3b2 100644 --- a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift +++ b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift @@ -22,6 +22,9 @@ internal struct PlaybackUIView: View { /// Optional authorization token if required to fetch the video details. private var authorizationToken: String? + /// Optional user ID to be tracked in analytics + private var userId: String? + /// Observed object to manage the video player plugins. @ObservedObject private var pluginManager = VideoPlayerPluginManager.shared @@ -40,11 +43,12 @@ internal struct PlaybackUIView: View { - entryId: The entry ID of the video to be played. - authorizationToken: Optional authorization token if required to fetch the video details. */ - internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, onError: ((PlayBackAPIError) -> Void)?) { + internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, userId: String?, onError: ((PlayBackAPIError) -> Void)?) { self.entryId = entryId self.authorizationToken = authorizationToken self.onError = onError self.mediaTitle = mediaTitle + self.userId = userId } /// The body of the view. @@ -58,7 +62,7 @@ internal struct PlaybackUIView: View { } else { if let videoURL = videoURL { if let plugin = pluginManager.selectedPlugin { - plugin.playerView(hlsURLString: videoURL.absoluteString, title: self.mediaTitle ?? "") + plugin.playerView(hlsURLString: videoURL.absoluteString, title: self.mediaTitle ?? "", userId: self.userId) } else { ErrorUIView(errorMessage: "No plugin selected") .background(Color.white) From 82ac864947b48d03127f453904fb2a217de3e7b1 Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Tue, 19 Nov 2024 14:44:02 +0200 Subject: [PATCH 2/6] [CORE-5162] Changes requested by @artem-y-pamediagroup --- .../Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift index 42e0231..9bf5494 100644 --- a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift +++ b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitMovinPlayerView.swift @@ -62,10 +62,6 @@ public struct BitMovinPlayerView: View { uiConfig.hideFirstFrame = true playerConfig.styleConfig.userInterfaceConfig = uiConfig - let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK") - - let analytics: BitmovinPlayerAnalytics.AnalyticsPlayerConfig - // Create player based on player and analytics configurations self.player = PlayerFactory.createPlayer( playerConfig: playerConfig From 6fcd407de3911242b4a96126c750aa7ecf87d49a Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Tue, 19 Nov 2024 15:07:04 +0200 Subject: [PATCH 3/6] [CORE-5162] Updated entry id for tests --- Tests/PlaybackSDKTests/TestConfig.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/PlaybackSDKTests/TestConfig.swift b/Tests/PlaybackSDKTests/TestConfig.swift index 7d5e217..2975275 100644 --- a/Tests/PlaybackSDKTests/TestConfig.swift +++ b/Tests/PlaybackSDKTests/TestConfig.swift @@ -9,5 +9,5 @@ import Foundation internal struct TestConfig { static let testAPIKey = "EJEZPIezBkaf0EQ7ey5Iu2MDA2ARUkgc79eyDOnG" - static let testEntryID = "0_qt9cy11s" + static let testEntryID = "0_cmk35zei" } From 7878a78cb544f41736d6d0b69cc91656793cd516 Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Thu, 21 Nov 2024 11:26:08 +0200 Subject: [PATCH 4/6] [CORE-5162] Changes requested by @StefanoStream --- Sources/PlaybackSDK/PlayBackSDKManager.swift | 4 ++-- .../BitMovinPlugin/BitmovinPlayerPlugin.swift | 8 ++++---- Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift | 2 +- Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/PlaybackSDK/PlayBackSDKManager.swift b/Sources/PlaybackSDK/PlayBackSDKManager.swift index 666b928..181aab5 100644 --- a/Sources/PlaybackSDK/PlayBackSDKManager.swift +++ b/Sources/PlaybackSDK/PlayBackSDKManager.swift @@ -151,7 +151,7 @@ public class PlayBackSDKManager { entryID: String, authorizationToken: String? = nil, mediaTitle: String? = nil, - userId: String? = nil, + viewerId: String? = nil, onError: ((PlayBackAPIError) -> Void)? ) -> some View { @@ -159,7 +159,7 @@ public class PlayBackSDKManager { entryId: entryID, authorizationToken: authorizationToken, mediaTitle: mediaTitle, - userId: userId, + viewerId: viewerId, onError: onError ) .id(entryID) diff --git a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift index 910f627..3e78ef9 100644 --- a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift @@ -39,23 +39,23 @@ public class BitmovinPlayerPlugin: VideoPlayerPlugin { playerConfig.styleConfig.userInterfaceConfig = uiConfig } - private func createAnalyticsConfig(userId: String? = nil) -> AnalyticsPlayerConfig { + private func createAnalyticsConfig(viewerId: String? = nil) -> AnalyticsPlayerConfig { guard let licenseKey = PlayBackSDKManager.shared.bitmovinLicense else { return .disabled } - let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK", customUserId: userId) + let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK", customUserId: viewerId) let analytics: BitmovinPlayerAnalytics.AnalyticsPlayerConfig = licenseKey != nil ? .enabled(analyticsConfig: AnalyticsConfig(licenseKey: licenseKey), defaultMetadata: defaultMetadata) : .disabled return analytics } - public func playerView(hlsURLString: String, title: String = "", userId: String? = nil) -> AnyView { + public func playerView(hlsURLString: String, title: String = "", viewerId: String? = nil) -> AnyView { // Create player based on player and analytics configurations let player = PlayerFactory.createPlayer( playerConfig: playerConfig, - analytics: self.createAnalyticsConfig(userId: userId) + analytics: self.createAnalyticsConfig(viewerId: viewerId) ) self.player = player diff --git a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift index e8accd2..27599d6 100644 --- a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift @@ -19,7 +19,7 @@ public protocol VideoPlayerPlugin: AnyObject { // TODO: add event /// func handleEvent(event: BitmovinPlayerCore.PlayerEvent) - func playerView(hlsURLString: String, title: String, userId: String?) -> AnyView + func playerView(hlsURLString: String, title: String, viewerId: String?) -> AnyView func play() diff --git a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift index 9fef3b2..7e4e380 100644 --- a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift +++ b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift @@ -23,7 +23,7 @@ internal struct PlaybackUIView: View { private var authorizationToken: String? /// Optional user ID to be tracked in analytics - private var userId: String? + private var viewerId: String? /// Observed object to manage the video player plugins. @ObservedObject private var pluginManager = VideoPlayerPluginManager.shared @@ -43,12 +43,12 @@ internal struct PlaybackUIView: View { - entryId: The entry ID of the video to be played. - authorizationToken: Optional authorization token if required to fetch the video details. */ - internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, userId: String?, onError: ((PlayBackAPIError) -> Void)?) { + internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, viewerId: String?, onError: ((PlayBackAPIError) -> Void)?) { self.entryId = entryId self.authorizationToken = authorizationToken self.onError = onError self.mediaTitle = mediaTitle - self.userId = userId + self.viewerId = viewerId } /// The body of the view. @@ -62,7 +62,7 @@ internal struct PlaybackUIView: View { } else { if let videoURL = videoURL { if let plugin = pluginManager.selectedPlugin { - plugin.playerView(hlsURLString: videoURL.absoluteString, title: self.mediaTitle ?? "", userId: self.userId) + plugin.playerView(hlsURLString: videoURL.absoluteString, title: self.mediaTitle ?? "", viewerId: self.viewerId) } else { ErrorUIView(errorMessage: "No plugin selected") .background(Color.white) From a8389746464cdc9a63dd343b0c032c76c843d60b Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Fri, 22 Nov 2024 11:24:19 +0200 Subject: [PATCH 5/6] [CORE-5162] Renamed parameter --- Sources/PlaybackSDK/PlayBackSDKManager.swift | 4 ++-- .../BitMovinPlugin/BitmovinPlayerPlugin.swift | 8 ++++---- .../PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift | 2 +- Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift | 10 ++++++---- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Sources/PlaybackSDK/PlayBackSDKManager.swift b/Sources/PlaybackSDK/PlayBackSDKManager.swift index 181aab5..dcc9af4 100644 --- a/Sources/PlaybackSDK/PlayBackSDKManager.swift +++ b/Sources/PlaybackSDK/PlayBackSDKManager.swift @@ -151,7 +151,7 @@ public class PlayBackSDKManager { entryID: String, authorizationToken: String? = nil, mediaTitle: String? = nil, - viewerId: String? = nil, + analyticsViewerId: String? = nil, onError: ((PlayBackAPIError) -> Void)? ) -> some View { @@ -159,7 +159,7 @@ public class PlayBackSDKManager { entryId: entryID, authorizationToken: authorizationToken, mediaTitle: mediaTitle, - viewerId: viewerId, + analyticsViewerId: analyticsViewerId, onError: onError ) .id(entryID) diff --git a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift index 3e78ef9..dc2fd2a 100644 --- a/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/BitMovinPlugin/BitmovinPlayerPlugin.swift @@ -39,23 +39,23 @@ public class BitmovinPlayerPlugin: VideoPlayerPlugin { playerConfig.styleConfig.userInterfaceConfig = uiConfig } - private func createAnalyticsConfig(viewerId: String? = nil) -> AnalyticsPlayerConfig { + private func createAnalyticsConfig(analyticsViewerId: String? = nil) -> AnalyticsPlayerConfig { guard let licenseKey = PlayBackSDKManager.shared.bitmovinLicense else { return .disabled } - let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK", customUserId: viewerId) + let defaultMetadata = DefaultMetadata(cdnProvider: "PlaybackSDK", customUserId: analyticsViewerId) let analytics: BitmovinPlayerAnalytics.AnalyticsPlayerConfig = licenseKey != nil ? .enabled(analyticsConfig: AnalyticsConfig(licenseKey: licenseKey), defaultMetadata: defaultMetadata) : .disabled return analytics } - public func playerView(hlsURLString: String, title: String = "", viewerId: String? = nil) -> AnyView { + public func playerView(hlsURLString: String, title: String = "", analyticsViewerId: String? = nil) -> AnyView { // Create player based on player and analytics configurations let player = PlayerFactory.createPlayer( playerConfig: playerConfig, - analytics: self.createAnalyticsConfig(viewerId: viewerId) + analytics: self.createAnalyticsConfig(analyticsViewerId: analyticsViewerId) ) self.player = player diff --git a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift index 27599d6..e4f3f5f 100644 --- a/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift +++ b/Sources/PlaybackSDK/Player Plugin/VideoPlayerPlugin.swift @@ -19,7 +19,7 @@ public protocol VideoPlayerPlugin: AnyObject { // TODO: add event /// func handleEvent(event: BitmovinPlayerCore.PlayerEvent) - func playerView(hlsURLString: String, title: String, viewerId: String?) -> AnyView + func playerView(hlsURLString: String, title: String, analyticsViewerId: String?) -> AnyView func play() diff --git a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift index 7e4e380..79f440c 100644 --- a/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift +++ b/Sources/PlaybackSDK/PlayerUIView/PlaybackUIView.swift @@ -23,7 +23,7 @@ internal struct PlaybackUIView: View { private var authorizationToken: String? /// Optional user ID to be tracked in analytics - private var viewerId: String? + private var analyticsViewerId: String? /// Observed object to manage the video player plugins. @ObservedObject private var pluginManager = VideoPlayerPluginManager.shared @@ -43,12 +43,12 @@ internal struct PlaybackUIView: View { - entryId: The entry ID of the video to be played. - authorizationToken: Optional authorization token if required to fetch the video details. */ - internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, viewerId: String?, onError: ((PlayBackAPIError) -> Void)?) { + internal init(entryId: String, authorizationToken: String?, mediaTitle: String?, analyticsViewerId: String?, onError: ((PlayBackAPIError) -> Void)?) { self.entryId = entryId self.authorizationToken = authorizationToken self.onError = onError self.mediaTitle = mediaTitle - self.viewerId = viewerId + self.analyticsViewerId = analyticsViewerId } /// The body of the view. @@ -62,7 +62,9 @@ internal struct PlaybackUIView: View { } else { if let videoURL = videoURL { if let plugin = pluginManager.selectedPlugin { - plugin.playerView(hlsURLString: videoURL.absoluteString, title: self.mediaTitle ?? "", viewerId: self.viewerId) + plugin.playerView(hlsURLString: videoURL.absoluteString, + title: self.mediaTitle ?? "", + analyticsViewerId: self.analyticsViewerId) } else { ErrorUIView(errorMessage: "No plugin selected") .background(Color.white) From 8ebcb8309e1c601d163ca8cf0518dfe3cf5a1dba Mon Sep 17 00:00:00 2001 From: Oleksandr Kharchenko Date: Fri, 22 Nov 2024 11:44:40 +0200 Subject: [PATCH 6/6] [CORE-5162] Fixed naming in comments --- Sources/PlaybackSDK/PlayBackSDKManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/PlaybackSDK/PlayBackSDKManager.swift b/Sources/PlaybackSDK/PlayBackSDKManager.swift index dcc9af4..58af4f2 100644 --- a/Sources/PlaybackSDK/PlayBackSDKManager.swift +++ b/Sources/PlaybackSDK/PlayBackSDKManager.swift @@ -139,13 +139,13 @@ public class PlayBackSDKManager { - Parameters: - entryID: The unique identifier of the video entry to be loaded. - authorizationToken: The token used for authorization to access the video content. - - userId: User identifier to be tracked in analytics + - analyticsViewerId: User identifier to be tracked in analytics - Returns: A view representing the video player configured with the provided entry ID and authorization token. Example usage: ```swift - let playerView = loadPlayer(entryID: "exampleEntryID", authorizationToken: "exampleToken", userId: "1234abcd") + let playerView = loadPlayer(entryID: "exampleEntryID", authorizationToken: "exampleToken", analyticsViewerId: "1234abcd") */ public func loadPlayer( entryID: String,