Skip to content

Commit

Permalink
[DuckPlayer] 21. Allow First video (#3249)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1204099484721401/1208057529481154/f
**Description**:
Do not show the video overlays when navigating to YouTube via "Watch in
YouTube" links.
  • Loading branch information
afterxleep authored Aug 21, 2024
1 parent 7dc4fec commit f3ab013
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 3 deletions.
21 changes: 20 additions & 1 deletion DuckDuckGo/DuckPlayer/DuckPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct InitialPlayerSettings: Codable {
}

let userValues: UserValues
let ui: UIValues
let settings: PlayerSettings
let platform: Platform
let locale: Locale
Expand All @@ -69,6 +70,13 @@ public struct UserValues: Codable {
let askModeOverlayHidden: Bool
}

public struct UIValues: Codable {
enum CodingKeys: String, CodingKey {
case allowFirstVideo
}
let allowFirstVideo: Bool
}

public enum DuckPlayerReferrer {
case youtube, other
}
Expand Down Expand Up @@ -193,6 +201,12 @@ final class DuckPlayer: DuckPlayerProtocol {
askModeOverlayHidden: settings.askModeOverlayHidden
)
}

private func encodeUIValues() -> UIValues {
UIValues(
allowFirstVideo: settings.allowFirstVideo
)
}

@MainActor
private func encodedPlayerSettings(with webView: WKWebView?) async -> InitialPlayerSettings {
Expand All @@ -203,7 +217,12 @@ final class DuckPlayer: DuckPlayerProtocol {
let locale = InitialPlayerSettings.Locale.en
let playerSettings = InitialPlayerSettings.PlayerSettings(pip: pip)
let userValues = encodeUserValues()
return InitialPlayerSettings(userValues: userValues, settings: playerSettings, platform: platform, locale: locale)
let uiValues = encodeUIValues()
return InitialPlayerSettings(userValues: userValues,
ui: uiValues,
settings: playerSettings,
platform: platform,
locale: locale)
}

// Accessing WKMessage needs main thread
Expand Down
17 changes: 15 additions & 2 deletions DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ final class DuckPlayerNavigationHandler {
return
}

// This is passed to the FE overlay at init to disable the overlay for one video
duckPlayer.settings.allowFirstVideo = false

if let (videoID, _) = url.youtubeVideoParams,
videoID == lastHandledVideoID {
os_log("DP: URL (%s) already handled, skipping", log: .duckPlayerLog, type: .debug, url.absoluteString)
Expand All @@ -118,7 +121,8 @@ final class DuckPlayerNavigationHandler {
// These should not be handled by DuckPlayer
if url.isYoutubeVideo,
url.hasWatchInYoutubeQueryParameter {
return
duckPlayer.settings.allowFirstVideo = true
return
}

if url.isYoutubeVideo,
Expand All @@ -143,6 +147,9 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {

os_log("DP: Handling DuckPlayer Player Navigation for %s", log: .duckPlayerLog, type: .debug, navigationAction.request.url?.absoluteString ?? "")

// This is passed to the FE overlay at init to disable the overlay for one video
duckPlayer.settings.allowFirstVideo = false

guard let url = navigationAction.request.url else { return }

guard featureFlagger.isFeatureOn(.duckPlayer) else {
Expand All @@ -167,6 +174,8 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
if let videoParameterItem = queryItems.first(where: { $0.name == Constants.watchInYoutubeVideoParameter }),
let id = videoParameterItem.value,
let newURL = URL.youtube(id, timestamp: nil).addingWatchInYoutubeQueryParameter() {
// These links should always skip the overlay
duckPlayer.settings.allowFirstVideo = true
Pixel.fire(pixel: Pixel.Event.duckPlayerWatchOnYoutube)
webView.load(URLRequest(url: newURL))
return
Expand Down Expand Up @@ -220,6 +229,9 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
return
}

// This is passed to the FE overlay at init to disable the overlay for one video
duckPlayer.settings.allowFirstVideo = false

if let (videoID, _) = url.youtubeVideoParams,
videoID == lastHandledVideoID,
!url.hasWatchInYoutubeQueryParameter {
Expand All @@ -229,9 +241,10 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
}

// Handle Youtube internal links like "Age restricted" and "Copyright restricted" videos
// These should not be handled by DuckPlayer
// These should not be handled by DuckPlayer and not include overlays
if url.isYoutubeVideo,
url.hasWatchInYoutubeQueryParameter {
duckPlayer.settings.allowFirstVideo = true
completion(.allow)
return
}
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/DuckPlayer/DuckPlayerSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ protocol DuckPlayerSettingsProtocol: AnyObject {
var duckPlayerSettingsPublisher: AnyPublisher<Void, Never> { get }
var mode: DuckPlayerMode { get }
var askModeOverlayHidden: Bool { get }
var allowFirstVideo: Bool { get set }

init(appSettings: AppSettings, privacyConfigManager: PrivacyConfigurationManaging)

Expand Down Expand Up @@ -133,6 +134,8 @@ final class DuckPlayerSettings: DuckPlayerSettingsProtocol {
}
}

var allowFirstVideo: Bool = false

private func registerConfigPublisher() {
isFeatureEnabledCancellable = privacyConfigManager.updatesPublisher
.map { [weak privacyConfigManager] in
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/DuckPlayer/YoutubeOverlayUserScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ final class YoutubeOverlayUserScript: NSObject, Subfeature {
weak var webView: WKWebView?

let messageOriginPolicy: MessageOriginPolicy = .only(rules: [
.exact(hostname: "sosbourne.duckduckgo.com"),
.exact(hostname: DuckPlayerSettings.OriginDomains.duckduckgo),
.exact(hostname: DuckPlayerSettings.OriginDomains.youtube),
.exact(hostname: DuckPlayerSettings.OriginDomains.youtubeMobile)
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGoTests/DuckPlayerMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ final class MockDuckPlayerSettings: DuckPlayerSettingsProtocol {

var mode: DuckPlayerMode = .disabled
var askModeOverlayHidden: Bool = false
var allowFirstVideo: Bool = false

init(appSettings: AppSettings = AppSettingsMock(), privacyConfigManager: any BrowserServicesKit.PrivacyConfigurationManaging) {}
func triggerNotification() {}
Expand Down

0 comments on commit f3ab013

Please sign in to comment.