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

[Duckplayer] 8. Age restricted videos #3111

Merged
merged 57 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
471a5eb
First batch of pixels
afterxleep Jul 4, 2024
b4f5626
Watch From SERP pixel
afterxleep Jul 9, 2024
3494df7
Merge branch 'main' into daniel/duckplayer/5.pixels
afterxleep Jul 9, 2024
70c739e
Update package
afterxleep Jul 9, 2024
5dbb45a
Test fix
afterxleep Jul 9, 2024
593d755
Fix lint issue
afterxleep Jul 9, 2024
a8141ce
Add first launch pixel
afterxleep Jul 10, 2024
29d5d3a
Add Settings Pixels
afterxleep Jul 10, 2024
16d3f98
Settings Pixels
afterxleep Jul 10, 2024
e462866
DuckPlayer from non-SERP
afterxleep Jul 10, 2024
239c8c0
duckPlayerViewFromYoutubeAutomatic
afterxleep Jul 10, 2024
f41a482
Initial Setup Updates
afterxleep Jul 10, 2024
310be79
Settings
afterxleep Jul 10, 2024
d21ce8b
Split Overlay and Player Settings
afterxleep Jul 10, 2024
7c59947
Remove PiP Settings
afterxleep Jul 10, 2024
3c4eee0
Merge branch 'main' into daniel/duckplayer/6.init.updates
afterxleep Jul 10, 2024
a47c7be
Packages
afterxleep Jul 10, 2024
ff9e04f
Handle Watch in Youtube Action
afterxleep Jul 16, 2024
24441f5
Handle DuckPlayer internal links
afterxleep Jul 16, 2024
169d60d
Reset DuckPlayer on launch
afterxleep Jul 17, 2024
81e29d4
Merge branch 'main' into daniel/duckplayer/6.init.updates
afterxleep Jul 17, 2024
c20c430
Fix Watch in DP button
afterxleep Jul 17, 2024
a3748bf
Remove uneeded code
afterxleep Jul 17, 2024
fa616f4
Open Settings and OpenInfo Mesasges
afterxleep Jul 17, 2024
489fd5e
Open DuckPlayer Settings
afterxleep Jul 17, 2024
69c5276
Pass tabID to navigation handler
afterxleep Jul 17, 2024
1fccdac
Move DuckPlayer one level up to TabManager
afterxleep Jul 17, 2024
62671f5
Fix Watch in Youtube Action
afterxleep Jul 18, 2024
5e48897
Move completion handlers out of navigation
afterxleep Jul 18, 2024
b06cdff
Updated DuckHandler Tests
afterxleep Jul 19, 2024
a14d59c
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
5ae8fd2
MOAR tests
afterxleep Jul 19, 2024
368972f
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
c06830e
Enable Info Button
afterxleep Jul 19, 2024
a8d860f
Remove redundant checks
afterxleep Jul 19, 2024
a88c7da
Removed unused vars
afterxleep Jul 19, 2024
0e9f1f6
Update comment
afterxleep Jul 19, 2024
bee6056
Update comment
afterxleep Jul 19, 2024
ffa5fa2
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
181ab0f
Fixed double if
afterxleep Jul 19, 2024
8cf99c6
Cleanup
afterxleep Jul 19, 2024
ca17840
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
5531745
Merge branch 'daniel/duckplayer/7.settings' into daniel/duckplayer/8.…
afterxleep Jul 19, 2024
58c00de
Merge branch 'main' into daniel/duckplayer/6.init.updates
afterxleep Jul 19, 2024
9197f2e
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
3171862
Merge branch 'daniel/duckplayer/7.settings' into daniel/duckplayer/8.…
afterxleep Jul 19, 2024
b837c2b
Fix incorrect merge
afterxleep Jul 19, 2024
563f75a
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
e263ce8
Merge branch 'daniel/duckplayer/7.settings' into daniel/duckplayer/8.…
afterxleep Jul 19, 2024
c106f3b
Link duckPlayer host onAppear
afterxleep Jul 19, 2024
011d6c2
Tests are now passing
afterxleep Jul 19, 2024
872138e
Remove / from path
afterxleep Jul 19, 2024
6963279
Merge branch 'daniel/duckplayer/6.init.updates' into daniel/duckplaye…
afterxleep Jul 19, 2024
da5d000
Merge branch 'daniel/duckplayer/7.settings' into daniel/duckplayer/8.…
afterxleep Jul 19, 2024
9571a5b
Merge branch 'main' into daniel/duckplayer/8.age.restricted.videos
afterxleep Jul 19, 2024
b5416a7
Remove C.S.S direct import
afterxleep Jul 19, 2024
02b7d8d
Merge branch 'main' into daniel/duckplayer/8.age.restricted.videos
afterxleep Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 58 additions & 28 deletions DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ final class DuckPlayerNavigationHandler {
static let httpMethod = "GET"
static let watchInYoutubePath = "openInYoutube"
static let watchInYoutubeVideoParameter = "v"
static let urlInternalReferrer = "embeds_referring_euri"
}

init(duckPlayer: DuckPlayerProtocol) {
Expand Down Expand Up @@ -96,6 +97,20 @@ final class DuckPlayerNavigationHandler {
performNavigation(duckPlayerRequest, responseHTML: html, webView: webView)
}

func hasEmbedsReferringEuriParameter(urlString: String) -> Bool {
guard let url = URL(string: urlString),
let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems else {
return false
}

for queryItem in queryItems where queryItem.name == Constants.urlInternalReferrer {
return true
}

return false
}

}

extension DuckPlayerNavigationHandler: DuckNavigationHandling {
Expand All @@ -107,10 +122,18 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {

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

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

// Handle Youtube internal links like "Age restricted" and "Copyright restricted" videos
// These should not be handled by DuckPlayer
if url.isYoutubeVideo,
hasEmbedsReferringEuriParameter(urlString: url.absoluteString) {
return
}

// Handle Open in Youtube Links
// duck://player/openInYoutube?v=12345
if let url = navigationAction.request.url,
url.scheme == "duck" {
if url.scheme == "duck" {
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)

if urlComponents?.path == "/\(Constants.watchInYoutubePath)",
Expand All @@ -127,8 +150,7 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
}

// Daily Unique View Pixel
if let url = navigationAction.request.url,
url.isDuckPlayer,
if url.isDuckPlayer,
duckPlayer.settings.mode != .disabled {
let setting = duckPlayer.settings.mode == .enabled ? Constants.duckPlayerAlwaysString : Constants.duckPlayerDefaultString
DailyPixel.fire(pixel: Pixel.Event.duckPlayerDailyUniqueView, withAdditionalParameters: [Constants.settingsKey: setting])
Expand All @@ -141,8 +163,7 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
}

// If DuckPlayer is Enabled or in ask mode, render the video
if let url = navigationAction.request.url,
url.isDuckURLScheme,
if url.isDuckURLScheme,
duckPlayer.settings.mode == .enabled || duckPlayer.settings.mode == .alwaysAsk,
!isDuckPlayerTemporarilyDisabled {
let newRequest = Self.makeDuckPlayerRequest(from: URLRequest(url: url))
Expand All @@ -154,8 +175,7 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
}

// DuckPlayer is disabled, so we redirect to the video in YouTube
if let url = navigationAction.request.url,
let (videoID, timestamp) = url.youtubeVideoParams,
if let (videoID, timestamp) = url.youtubeVideoParams,
duckPlayer.settings.mode == .disabled {
os_log("DP: is Disabled. We should load original video for %s", log: .duckPlayerLog, type: .debug)
handleURLChange(url: URL.youtube(videoID, timestamp: timestamp), webView: webView)
Expand All @@ -167,17 +187,25 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
// such as changes triggered via JS
@MainActor
func handleURLChange(url: URL?, webView: WKWebView) {

guard let url else { return }

// Handle Youtube internal links like "Age restricted" and "Copyright restricted" videos
// These should not be handled by DuckPlayer
if url.isYoutubeVideo,
hasEmbedsReferringEuriParameter(urlString: url.absoluteString) {
return
}

// Do not handle the URL if the video was just handled
if let url = url,
url.isYoutubeVideo || url.isDuckPlayer,
if url.isYoutubeVideo || url.isDuckPlayer,
let (videoID, _) = url.youtubeVideoParams,
lastHandledVideoID == videoID,
!isDuckPlayerTemporarilyDisabled {
return
}

if let url = url, url.isYoutubeVideo,
if url.isYoutubeVideo,
!url.isDuckPlayer,
let (videoID, timestamp) = url.youtubeVideoParams,
duckPlayer.settings.mode == .enabled || duckPlayer.settings.mode == .alwaysAsk {
Expand Down Expand Up @@ -211,36 +239,38 @@ extension DuckPlayerNavigationHandler: DuckNavigationHandling {
func handleDecidePolicyFor(_ navigationAction: WKNavigationAction,
webView: WKWebView) {

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

// Handle Youtube internal links like "Age restricted" and "Copyright restricted" videos
// These should not be handled by DuckPlayer
if url.isYoutubeVideo,
hasEmbedsReferringEuriParameter(urlString: url.absoluteString) {
return
}

// Do not handle the URL if the video was just handled
if let url = navigationAction.request.url,
url.isYoutubeVideo || url.isDuckPlayer,
let (videoID, _) = url.youtubeVideoParams,
if url.isYoutubeVideo || url.isDuckPlayer,
let (videoID, timestamp) = url.youtubeVideoParams,
lastHandledVideoID == videoID,
!isDuckPlayerTemporarilyDisabled {
return
}


// Pixel for Views From SERP
if let url = navigationAction.request.url,
navigationAction.request.allHTTPHeaderFields?[Constants.refererHeader] == Constants.SERPURL,
if navigationAction.request.allHTTPHeaderFields?[Constants.refererHeader] == Constants.SERPURL,
duckPlayer.settings.mode == .enabled, !url.isDuckPlayer {
Pixel.fire(pixel: Pixel.Event.duckPlayerViewFromSERP, debounce: 2)
}

// Pixel for views from Other Sites
if let url = navigationAction.request.url,
navigationAction.request.allHTTPHeaderFields?[Constants.refererHeader] != Constants.SERPURL,
duckPlayer.settings.mode == .enabled, !url.isDuckPlayer {
} else {
Pixel.fire(pixel: Pixel.Event.duckPlayerViewFromOther, debounce: 2)
}

if let url = navigationAction.request.url,
url.isYoutubeVideo,
!url.isDuckPlayer, let (videoID, timestamp) = url.youtubeVideoParams,
duckPlayer.settings.mode == .enabled || duckPlayer.settings.mode == .alwaysAsk {
os_log("DP: Handling decidePolicy for Duck Player with %s", log: .duckPlayerLog, type: .debug, url.absoluteString)
handleURLChange(url: URL.duckPlayer(videoID, timestamp: timestamp), webView: webView)
if url.isYoutubeVideo,
!url.isDuckPlayer,
let (videoID, timestamp) = url.youtubeVideoParams,
duckPlayer.settings.mode == .enabled || duckPlayer.settings.mode == .alwaysAsk {
os_log("DP: Handling decidePolicy for Duck Player with %s", log: .duckPlayerLog, type: .debug, url.absoluteString)
handleURLChange(url: URL.duckPlayer(videoID, timestamp: timestamp), webView: webView)
return
}
}
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/TabViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ class TabViewController: UIViewController {
resetNavigationBar()
delegate?.tabDidRequestShowingMenuHighlighter(tab: self)
tabModel.viewed = true

// Link DuckPlayer to current Tab
duckPlayerNavigationHandler.duckPlayer.setHostViewController(self)
}

override func buildActivities() -> [UIActivity] {
Expand Down
Loading