diff --git a/extension-manifest-v2/app/content-scripts/youtube.js b/extension-manifest-v2/app/content-scripts/youtube.js
index 93c461110..3b79583b8 100644
--- a/extension-manifest-v2/app/content-scripts/youtube.js
+++ b/extension-manifest-v2/app/content-scripts/youtube.js
@@ -1,26 +1,40 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+import detectWall from '@ghostery/ui/youtube/wall';
import { showIframe, closeIframe } from '@ghostery/ui/iframe';
-// Based on https://github.com/AdguardTeam/AdguardFilters/blob/e5ae8e3194f8d18bdcc660d4c42282e4a96ca5b9/AnnoyancesFilter/Popups/sections/antiadblock.txt#L2044
-const ADBLOCKER_WALL_SELECTORS = [
- 'ytd-watch-flexy:not([hidden]) ytd-enforcement-message-view-model > div.ytd-enforcement-message-view-model',
-];
+function isFeatureDisabled() {
+ return new Promise((resolve) => {
+ chrome.storage.local.get(['youtube_dont_show_again'], (storage) => {
+ resolve(storage.youtube_dont_show_again);
+ });
+ });
+}
-let isShown = false;
+if (!chrome.extension.inIncognitoContext) {
+ (async () => {
+ if (await isFeatureDisabled()) return;
-chrome.storage.local.get(['youtube_dont_show_again'], (storage) => {
- if (storage.youtube_dont_show_again || chrome.extension.inIncognitoContext) {
- return;
- }
+ window.addEventListener('yt-navigate-start', () => {
+ closeIframe();
+ }, true);
- window.addEventListener('yt-navigate-start', () => {
- isShown = false;
- closeIframe();
- }, true);
+ detectWall(async () => {
+ if (await isFeatureDisabled()) return;
- setInterval(() => {
- if (!isShown && document.querySelectorAll(ADBLOCKER_WALL_SELECTORS).length > 0) {
- showIframe(chrome.runtime.getURL(`app/templates/youtube.html?url=${encodeURIComponent(window.location.href)}`), '460px');
- isShown = true;
- }
- }, 2000);
-});
+ showIframe(
+ chrome.runtime.getURL(`app/templates/youtube.html?url=${encodeURIComponent(window.location.href)}`),
+ '460px',
+ );
+ });
+ })();
+}
diff --git a/extension-manifest-v2/app/youtube/components/message.js b/extension-manifest-v2/app/youtube/components/message.js
deleted file mode 100644
index b727576f4..000000000
--- a/extension-manifest-v2/app/youtube/components/message.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Ghostery Browser Extension
- * https://www.ghostery.com/
- *
- * Copyright 2017-present Ghostery GmbH. All rights reserved.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0
- */
-
-import { define, html, dispatch } from 'hybrids';
-
-export default define({
- tag: 'youtube-message',
- content: () => html`
-
-
-
-
-
-
-
-
-
-
- YouTube blocking you from watching ad-free videos?
-
-
-
-
-
-
- We know you rely on Ghostery for a smooth YouTube experience.
- Until a more refined solution emerges, here’s a temporary fix.
-
-
-
- 1.
-
- Allow Ghostery in private windows
-
-
-
-
-
-
-
-
-
-
- 2.
-
- Open YouTube in a private window
-
-
-
-
-
-
-
-
-
-
-
- Learn more about YouTube’s challenges to ad blockers
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `.css`
- .hr {
- background: #D4D6D9;
- height: 1px;
- align-self: stretch;
- }
- `,
-});
diff --git a/extension-manifest-v2/app/youtube/index.js b/extension-manifest-v2/app/youtube/index.js
index f77b2b1dd..6790179af 100644
--- a/extension-manifest-v2/app/youtube/index.js
+++ b/extension-manifest-v2/app/youtube/index.js
@@ -8,10 +8,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/
+
import { mount, html } from 'hybrids';
-import '@ghostery/ui/onboarding';
-import './components/message';
+import '@ghostery/ui/youtube';
import { setupIframe, closeIframe } from '@ghostery/ui/iframe';
setupIframe();
@@ -25,6 +25,7 @@ function openPrivateWindow() {
url,
},
});
+ closeIframe();
}
function openBlog(slug) {
@@ -46,12 +47,12 @@ function dontAsk() {
mount(document.body, {
content: () => html`
-
+ >
`,
});
diff --git a/extension-manifest-v3/src/background/helpers.js b/extension-manifest-v3/src/background/helpers.js
index b6d3a8dce..6d85911c0 100644
--- a/extension-manifest-v3/src/background/helpers.js
+++ b/extension-manifest-v3/src/background/helpers.js
@@ -16,6 +16,12 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
sendResponse(tab);
});
return true;
+ case 'openTabWithUrl':
+ chrome.tabs.create({ url: msg.url });
+ break;
+ case 'openPrivateWindowWithUrl':
+ chrome.windows.create({ url: msg.url, incognito: true });
+ break;
}
return false;
diff --git a/extension-manifest-v3/src/content_scripts/youtube.js b/extension-manifest-v3/src/content_scripts/youtube.js
new file mode 100644
index 000000000..df666f3ea
--- /dev/null
+++ b/extension-manifest-v3/src/content_scripts/youtube.js
@@ -0,0 +1,55 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+import { showIframe, closeIframe } from '@ghostery/ui/iframe';
+import detectWall from '@ghostery/ui/youtube/wall';
+
+async function isFeatureDisabled() {
+ const { options, youtubeDontAsk } = await chrome.storage.local.get([
+ 'options',
+ 'youtubeDontAsk',
+ ]);
+
+ if (
+ // User's choice to not show the wall
+ youtubeDontAsk ||
+ // Terms not accepted or paused domain
+ !options ||
+ !options.terms ||
+ options.paused.some(({ id }) => id.includes('youtube.com'))
+ ) {
+ return true;
+ }
+
+ return false;
+}
+
+// INFO: Safari always returns false for `inIncognitoContext`
+if (!chrome.extension.inIncognitoContext) {
+ (async () => {
+ if (await isFeatureDisabled()) return;
+
+ window.addEventListener('yt-navigate-start', () => closeIframe(), true);
+
+ detectWall(async () => {
+ if (await isFeatureDisabled()) return;
+
+ showIframe(
+ chrome.runtime.getURL(
+ `/pages/youtube/index.html?url=${encodeURIComponent(
+ window.location.href,
+ )}`,
+ ),
+ '460px',
+ );
+ });
+ })();
+}
diff --git a/extension-manifest-v3/src/manifest.chromium.json b/extension-manifest-v3/src/manifest.chromium.json
index 9a52f4ab8..05f239e16 100644
--- a/extension-manifest-v3/src/manifest.chromium.json
+++ b/extension-manifest-v3/src/manifest.chromium.json
@@ -91,7 +91,12 @@
"js": [
"content_scripts/whotracksme/reporting.js"
]
- }
+ },
+ {
+ "matches": ["*://www.youtube.com/*"],
+ "run_at": "document_start",
+ "js": ["content_scripts/youtube.js"]
+ }
],
"web_accessible_resources": [
{
@@ -103,7 +108,8 @@
"pages/autoconsent/index.html",
"pages/onboarding/index.html",
"pages/onboarding/iframe.html",
- "pages/onboarding/opera-serp.html"
+ "pages/onboarding/opera-serp.html",
+ "pages/youtube/index.html"
],
"all_frames": true,
"matches": [
diff --git a/extension-manifest-v3/src/manifest.firefox.json b/extension-manifest-v3/src/manifest.firefox.json
index e5f902a74..8c7cd37c4 100644
--- a/extension-manifest-v3/src/manifest.firefox.json
+++ b/extension-manifest-v3/src/manifest.firefox.json
@@ -73,7 +73,12 @@
"js": [
"content_scripts/whotracksme/reporting.js"
]
- }
+ },
+ {
+ "matches": ["*://www.youtube.com/*"],
+ "run_at": "document_start",
+ "js": ["content_scripts/youtube.js"]
+ }
],
"web_accessible_resources": [
"content_scripts/trackers-preview.js",
@@ -81,7 +86,8 @@
"pages/trackers-preview/index.html",
"pages/autoconsent/index.html",
"pages/onboarding/index.html",
- "pages/onboarding/iframe.html"
+ "pages/onboarding/iframe.html",
+ "pages/youtube/index.html"
],
"browser_specific_settings": {
"gecko": {
diff --git a/extension-manifest-v3/src/manifest.safari.json b/extension-manifest-v3/src/manifest.safari.json
index 3f7306561..1fd62689c 100644
--- a/extension-manifest-v3/src/manifest.safari.json
+++ b/extension-manifest-v3/src/manifest.safari.json
@@ -94,7 +94,12 @@
"js": [
"content_scripts/whotracksme/reporting.js"
]
- }
+ },
+ {
+ "matches": ["*://www.youtube.com/*"],
+ "run_at": "document_start",
+ "js": ["content_scripts/youtube.js"]
+ }
],
"web_accessible_resources": [
"content_scripts/whotracksme/ghostery-whotracksme.js",
@@ -103,7 +108,8 @@
"pages/trackers-preview/index.html",
"pages/autoconsent/index.html",
"pages/onboarding/index.html",
- "pages/onboarding/iframe.html"
+ "pages/onboarding/iframe.html",
+ "pages/youtube/index.html"
],
"content_security_policy" : {},
"browser_specific_settings": {
diff --git a/extension-manifest-v3/src/pages/youtube/index.html b/extension-manifest-v3/src/pages/youtube/index.html
new file mode 100644
index 000000000..60fa161ec
--- /dev/null
+++ b/extension-manifest-v3/src/pages/youtube/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Youtube Wall
+
+
+
+
diff --git a/extension-manifest-v3/src/pages/youtube/index.js b/extension-manifest-v3/src/pages/youtube/index.js
new file mode 100644
index 000000000..83c1722bb
--- /dev/null
+++ b/extension-manifest-v3/src/pages/youtube/index.js
@@ -0,0 +1,53 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+import { mount, html } from 'hybrids';
+
+import '@ghostery/ui/youtube';
+import { setupIframe, closeIframe } from '@ghostery/ui/iframe';
+
+function dontAsk() {
+ chrome.storage.local.set({
+ youtubeDontAsk: true,
+ });
+ closeIframe();
+}
+
+function openBlog(slug) {
+ chrome.runtime.sendMessage({
+ action: 'openTabWithUrl',
+ url: `https://www.ghostery.com/blog/${slug}?utm_source=gbe&utm_campaign=youtube`,
+ });
+}
+
+function openPrivateWindow() {
+ chrome.runtime.sendMessage({
+ action: 'openPrivateWindowWithUrl',
+ url: new URLSearchParams(window.location.search).get('url'),
+ });
+ closeIframe();
+}
+
+setupIframe();
+
+mount(document.body, {
+ content: () => html`
+
+
+
+ `,
+});
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 7d7fc6e54..7c0c0d63f 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -11,6 +11,8 @@
"./panel": "./src/modules/panel/index.js",
"./settings": "./src/modules/settings/index.js",
"./trackers-preview": "./src/modules/trackers-preview/index.js",
+ "./youtube": "./src/modules/youtube/index.js",
+ "./youtube/wall": "./src/modules/youtube/wall.js",
"./categories": "./src/utils/categories.js",
"./labels": "./src/utils/labels.js",
"./wheel": "./src/utils/wheel.js",
diff --git a/packages/ui/src/modules/youtube/components/wall.js b/packages/ui/src/modules/youtube/components/wall.js
new file mode 100644
index 000000000..97cf5ab35
--- /dev/null
+++ b/packages/ui/src/modules/youtube/components/wall.js
@@ -0,0 +1,107 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+import { html, dispatch } from 'hybrids';
+
+export default {
+ content: () => html`
+
+
+
+
+
+
+
+
+
+
+ YouTube blocking you from watching ad-free videos?
+
+
+
+
+
+
+ We know you rely on Ghostery for a smooth YouTube experience.
+ Until a more refined solution emerges, here’s a temporary fix.
+
+
+
+ 1.
+
+ Allow Ghostery in private windows
+
+
+
+
+
+
+
+
+
+
+ 2.
+
+ Open YouTube in a private window
+
+
+
+
+
+
+
+
+
+
+
+ Learn more about YouTube’s challenges to ad blockers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+};
diff --git a/packages/ui/src/modules/youtube/index.js b/packages/ui/src/modules/youtube/index.js
new file mode 100644
index 000000000..6f3ddb986
--- /dev/null
+++ b/packages/ui/src/modules/youtube/index.js
@@ -0,0 +1,23 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+import { define } from 'hybrids';
+
+import '../onboarding/index.js';
+
+// Components
+define.from(
+ import.meta.glob('./components/*.js', { eager: true, import: 'default' }),
+ {
+ prefix: 'ui-youtube',
+ root: 'components',
+ },
+);
diff --git a/packages/ui/src/modules/youtube/wall.js b/packages/ui/src/modules/youtube/wall.js
new file mode 100644
index 000000000..891b071b1
--- /dev/null
+++ b/packages/ui/src/modules/youtube/wall.js
@@ -0,0 +1,52 @@
+/**
+ * Ghostery Browser Extension
+ * https://www.ghostery.com/
+ *
+ * Copyright 2017-present Ghostery GmbH. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0
+ */
+
+const SELECTORS = [
+ // Based on https://github.com/AdguardTeam/AdguardFilters/blob/e5ae8e3194f8d18bdcc660d4c42282e4a96ca5b9/AnnoyancesFilter/Popups/sections/antiadblock.txt#L2044
+ 'ytd-watch-flexy:not([hidden]) ytd-enforcement-message-view-model > div.ytd-enforcement-message-view-model',
+
+ 'yt-playability-error-supported-renderers#error-screen ytd-enforcement-message-view-model',
+ 'tp-yt-paper-dialog .ytd-enforcement-message-view-model',
+];
+const DELAY = 1000; // 1 second
+
+export default function detectWall(cb) {
+ let timeout = null;
+
+ const observer = new MutationObserver(() => {
+ if (timeout) return;
+
+ timeout = setTimeout(() => {
+ if (document.querySelector(SELECTORS)?.clientHeight > 0) {
+ try {
+ cb();
+ } catch (e) {
+ /* ignore */
+ }
+ } else {
+ timeout = null;
+ }
+ }, DELAY);
+ });
+
+ document.addEventListener('yt-navigate-start', () => {
+ clearTimeout(timeout);
+ timeout = null;
+ });
+
+ document.addEventListener('DOMContentLoaded', () => {
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ attributeFilter: ['src', 'style'],
+ });
+ });
+}
diff --git a/packages/ui/src/utils/iframe.js b/packages/ui/src/utils/iframe.js
index a00ed6c39..77562ec63 100644
--- a/packages/ui/src/utils/iframe.js
+++ b/packages/ui/src/utils/iframe.js
@@ -10,6 +10,11 @@
*/
export function showIframe(url, width = '440px') {
+ // Prevent multiple iframes be shown at the same time
+ if (document.querySelector('ghostery-iframe-wrapper')) {
+ return;
+ }
+
const wrapper = document.createElement('ghostery-iframe-wrapper');
const shadowRoot = wrapper.attachShadow({ mode: 'closed' });
@@ -93,12 +98,16 @@ export function showIframe(url, width = '440px') {
if (e.data.reload) {
window.location.reload();
} else {
- setTimeout(() => wrapper.parentElement.removeChild(wrapper), 0);
+ if (wrapper.parentElement) {
+ setTimeout(() => wrapper.parentElement.removeChild(wrapper), 0);
+ }
}
break;
case 'ghostery-clear-iframe':
if (iframe.src === e.data.url) {
- setTimeout(() => wrapper.parentElement.removeChild(wrapper), 0);
+ if (wrapper.parentElement) {
+ setTimeout(() => wrapper.parentElement.removeChild(wrapper), 0);
+ }
}
break;
default: