Fork Sync: Update from parent repository - #334
Conversation
Related commit: gorhill@10ae629 Upstream: gorhill/uBlock@615a71a
Brave can't be told apart from Chrome through the user agent string, so detection uses `navigator.brave` with `navigator.userAgentData.brands` as fallback. Both are synchronous, unlike `navigator.brave.isBrave()` -- the flavor must be settled before filter lists are compiled and cached. Brave still offers uBO in MV2, and a considerable number of Brave users run Brave Shields and uBO at the same time. Filters which are safe on their own can conflict when both blockers apply them, and list maintainers currently have no way to express that: uBlockOrigin/uAssets#34162 Upstream: gorhill/uBlock@0c56103
Related issue: uBlockOrigin/uBOL-home#749 Upstream: gorhill/uBlock@f94bf63
Related issue: uBlockOrigin/uBOL-home#754 Upstream: gorhill/uBlock@39a0106
Related issue: uBlockOrigin/uBlock-issues#4090 Upstream: gorhill/uBlock@57ade5f
All supported browsers support user stylesheets, and in any case filter list maintainers shouldn't have to worry about whether user stylesheets are supported or not. Upstream: gorhill/uBlock@fb09b09
Upstream: gorhill/uBlock@ed52e20
Upstream: gorhill/uBlock@89e149e
Upstream: gorhill/uBlock@a2fb47c
Upstream: gorhill/uBlock@3ca8fb7
Related commit: gorhill@933efff4dd Upstream: gorhill/uBlock@fe277a4
… sources Exception filters must never cause actual filters to be created. Reported via email by "syvb": > If you use both ~ and #@# in a filter rule, they cancel each other > out and the filter still runs. But the check for trusted filter rules > ignores all rules with #@#, even if they also use ~. So if you use > both ~ and #@# in the same filter rule it will still run and can use > trusted scriptlets, even when not in a trusted filter list. > > E.g. this filter runs JS on every page, even when not part of a > trusted filter list: > > ~*#@#+js(trusted-create-html, body, <img src=x onerror="alert(document.domain)">) > > idk how big of a problem this is. but having ~ and #@# cancel each other out > doesn't seem like intended behavior anyways? > > thanks > [syvb] Upstream: gorhill/uBlock@a46d5c8
Upstream: gorhill/uBlock@23db37e
"uBlock Origin dev build" is no longer available in the Chrome Web store. Upstream: gorhill/uBlock@275bb2b
Upstream: gorhill/uBlock@7650840
Upstream: gorhill/uBlock@5b23c62
Upstream: gorhill/uBlock@638e128
Related issue: uBlockOrigin/uBlock-issues#4107 Upstream: gorhill/uBlock@c9eb5b2
Add gutter widget in editor when a filter is not supported on the current platform: uBlockOrigin/uBlock-issues#4096 Fix error count improperly updated when end of change is not at start of line: uBlockOrigin/uBlock-issues#4097 Add support for redirectable resources to require trusted source: gorhill@933efff4dd#r198472817 Detect mismatch between resources requiring trusted source and untrusted source at static filter parsing time. Upstream: gorhill/uBlock@3ab7319
Upstream: gorhill/uBlock@f06666f
1e115c7 to
913c147
Compare
"uBlock Origin dev build" is no longer available in the Chrome Web store.
"uBlock Origin dev build" is no longer available in the Chrome Web store.
|
Root cause found: the mirror chain was rooted at Fix (PR #333, cb6f9a1): the chain is now rooted at the current master tip and replays only upstream commits whose patch-id is not already on master ( |
"uBlock Origin dev build" is no longer available in the Chrome Web store.
|
anthropic debug - [puLL-Merge] - brave/uBlock@334 Diffdiff --git assets/assets.json assets/assets.json
index 8c183004546ca..bc9f004f5da04 100644
--- assets/assets.json
+++ assets/assets.json
@@ -754,11 +754,11 @@
"content": "filters",
"group": "regions",
"off": true,
- "title": "🇰🇷kr: List-KR Classic",
+ "title": "🇰🇷kr: 한국어 (Korean)",
"tags": "ads korean 한국어",
"lang": "ko",
- "contentURL": "https://cdn.jsdelivr.net/npm/@list-kr/filterslists@latest/dist/filterslist-uBlockOrigin-classic.txt",
- "supportURL": "https://github.com/List-KR/List-KR#readme"
+ "contentURL": "https://cdn.jsdelivr.net/npm/@filteringdev/filterslists-ko@latest/dist/filterslist-uBlockOrigin-classic.txt",
+ "supportURL": "https://github.com/FilteringDev/filterslists-KO#filteringdevfilterslists-ko"
},
"LTU-0": {
"content": "filters",
diff --git src/js/redirect-resources.js src/js/redirect-resources.js
index d9d835d81c1db..313d50ba6a0f0 100644
--- src/js/redirect-resources.js
+++ src/js/redirect-resources.js
@@ -99,6 +99,11 @@ export default new Map([
alias: 'google-ima3', /* adguard compatibility */
data: 'text',
} ],
+ [ 'google-ima-dai.js', {
+ alias: 'google-ima3-dai', /* adguard compatibility */
+ data: 'text',
+ requiresTrust: true,
+ } ],
[ 'googlesyndication_adsbygoogle.js', {
alias: [
'googlesyndication.com/adsbygoogle.js',
diff --git src/js/resources/prevent-addeventlistener.js src/js/resources/prevent-addeventlistener.js
index 7a9666ab71de1..1321edacaf9d5 100644
--- src/js/resources/prevent-addeventlistener.js
+++ src/js/resources/prevent-addeventlistener.js
@@ -91,8 +91,8 @@ function preventAddEventListener(
return parts.join('');
};
const shouldPrevent = (thisArg, type, handler) => {
- const matchesType = safe.RegExp_test.call(reType, type);
- const matchesHandler = safe.RegExp_test.call(rePattern, handler);
+ const matchesType = safe.RegExp_test(reType, type);
+ const matchesHandler = safe.RegExp_test(rePattern, handler);
const matchesEither = matchesType || matchesHandler;
const matchesBoth = matchesType && matchesHandler;
if ( safe.logLevel > 1 && matchesEither ) {
diff --git src/js/resources/prevent-clipboard-write.js src/js/resources/prevent-clipboard-write.js
index df6fbd1dea904..ca5432ab79add 100644
--- src/js/resources/prevent-clipboard-write.js
+++ src/js/resources/prevent-clipboard-write.js
@@ -54,19 +54,23 @@ function preventClipboardWrite(matches = '', ...varargs) {
const extraArgs = safe.parseVarargs(varargs);
const excludePattern = extraArgs.excludeMatches &&
safe.initPattern(extraArgs.excludeMatches);
+ const htmlTemplate = [
+ '<div style="background-color:beige;color:black;border:1px solid black;display:flex;font-family:sans-serif;font-size:medium;position:fixed;top:0;white-space:pre-wrap;width:100%;z-index:2147483647">',
+ '<span style="flex-grow:1;padding:0.5em 0 0.5em 0.5em;">${warning}</span>\n',
+ '<button style="font-size:32px;padding:0.5em">×</button>',
+ '</div>',
+ ].join('');
const domAlert = clipboardText => {
const doc = document;
- const div = doc.createElement('div');
- const span = doc.createElement('span');
- span.style = 'flex-grow:1;padding:0.5em 0 0.5em 0.5em;';
const domAlert = extraArgs.domAlert.replace(/\\n/g, '\n');
- const placeholder = /\$\{text\}/.exec(domAlert);
- if ( placeholder ) {
+ let html;
+ if ( domAlert.includes('${text}') ) {
const code = doc.createElement('code');
const styles = [
'background-color: #ddc',
'display: inline-block',
'font-family: monospace',
+ 'font-size: 100%',
'max-height: 8em',
'overflow: auto',
'padding: 0.25em',
@@ -77,29 +81,23 @@ function preventClipboardWrite(matches = '', ...varargs) {
}
code.style = styles.join(';');
code.textContent = clipboardText;
- span.append(
- domAlert.slice(0, placeholder.index),
- code,
- domAlert.slice(placeholder.index + placeholder[0].length)
+ html = htmlTemplate.replace('${warning}',
+ domAlert.replace('${text}', code.outerHTML)
);
} else {
- span.append(domAlert);
+ html = htmlTemplate.replace('${warning}', domAlert);
}
- const button = doc.createElement('button');
- button.style = 'font-size:32px;padding:0.5em';
- button.textContent = '×';
+ if ( currentAlert ) { currentAlert.remove(); }
+ const domParser = new DOMParser();
+ const fragment = domParser.parseFromString(html, 'text/html');
+ currentAlert = fragment.querySelector('div');
+ const button = currentAlert.querySelector('button');
button.addEventListener('click', ( ) => {
if ( currentAlert === null ) { return; }
currentAlert.remove();
currentAlert = null;
});
- div.append(span, button);
- div.style = 'background-color:beige;color:black;border:1px solid black;display:flex;font-family:sans-serif;font-size:medium;position:fixed;top:0;white-space:pre-wrap;width:100%;z-index:2147483647';
- doc.documentElement.append(div);
- if ( currentAlert ) {
- currentAlert.remove();
- }
- currentAlert = div;
+ doc.documentElement.append(currentAlert);
};
let currentAlert = null;
const prevent = text => {
diff --git src/js/resources/prevent-xhr.js src/js/resources/prevent-xhr.js
index e0bce3b8c9840..478470872a70f 100644
--- src/js/resources/prevent-xhr.js
+++ src/js/resources/prevent-xhr.js
@@ -25,7 +25,10 @@ import {
matchObjectPropertiesFn,
parsePropertiesToMatchFn,
} from './utils.js';
-import { proxyApplyFn } from './proxy-apply.js';
+import {
+ proxyApplyFn,
+ proxyToStringFn,
+} from './proxy-apply.js';
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
@@ -34,6 +37,62 @@ import { safeSelf } from './safe-self.js';
/******************************************************************************/
+export function modifyXhrResponseFn(
+ propsToMatch = '',
+ modifierFn = ''
+) {
+ if ( typeof propsToMatch !== 'string' ) { return; }
+ const safe = safeSelf();
+ if ( modifyXhrResponseFn.xhrInstances === undefined ) {
+ modifyXhrResponseFn.xhrInstances = new WeakMap();
+ }
+ const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url');
+ const NativeXMLHttpRequest = self.XMLHttpRequest;
+ const TrappedXMLHttpRequest = class XMLHttpRequest extends NativeXMLHttpRequest {
+ open(method, url, ...args) {
+ const haystack = { method, url };
+ if ( propsToMatch === '' ) {
+ safe.uboLog(`modifyXhrResponseFn() / Called: ${safe.JSON_stringify(haystack, null, 2)}`);
+ } else if ( matchObjectPropertiesFn(propNeedles, haystack) ) {
+ modifyXhrResponseFn.xhrInstances.set(this, modifierFn);
+ }
+ return super.open(method, url, ...args);
+ }
+ get response() {
+ const modifierFn = modifyXhrResponseFn.xhrInstances.get(this);
+ return modifierFn
+ ? modifierFn(this, super.response)
+ : super.response;
+ }
+ get responseText() {
+ const modifierFn = modifyXhrResponseFn.xhrInstances.get(this);
+ return modifierFn
+ ? modifierFn(this, super.responseText)
+ : super.responseText;
+ }
+ get responseXML() {
+ const modifierFn = modifyXhrResponseFn.xhrInstances.get(this);
+ return modifierFn
+ ? modifierFn(this, super.responseXML)
+ : super.responseXML;
+ }
+ };
+ proxyToStringFn(TrappedXMLHttpRequest.prototype.open, NativeXMLHttpRequest.prototype.open);
+ proxyToStringFn(TrappedXMLHttpRequest, NativeXMLHttpRequest);
+ self.XMLHttpRequest = TrappedXMLHttpRequest;
+}
+registerScriptlet(modifyXhrResponseFn, {
+ name: 'modify-xhr-response.fn',
+ dependencies: [
+ matchObjectPropertiesFn,
+ parsePropertiesToMatchFn,
+ proxyToStringFn,
+ safeSelf,
+ ],
+});
+
+/******************************************************************************/
+
function preventXhrFn(
trusted = false,
propsToMatch = '',
diff --git src/js/resources/proxy-apply.js src/js/resources/proxy-apply.js
index c64b043e341f9..9f32a643ff387 100644
--- src/js/resources/proxy-apply.js
+++ src/js/resources/proxy-apply.js
@@ -24,6 +24,32 @@ import { registerScriptlet } from './base.js';
/******************************************************************************/
+export function proxyToStringFn(proxiedFn, nativeFn) {
+ if ( proxyToStringFn.proxies === undefined ) {
+ proxyToStringFn.proxies = new WeakMap();
+ proxyToStringFn.nativeToString = Function.prototype.toString;
+ const proxiedToString = new Proxy(Function.prototype.toString, {
+ apply(target, thisArg) {
+ let proxied = thisArg;
+ for(;;) {
+ const fn = proxyToStringFn.proxies.get(proxied);
+ if ( fn === undefined ) { break; }
+ proxied = fn;
+ }
+ return proxyToStringFn.nativeToString.call(proxied);
+ }
+ });
+ proxyToStringFn.proxies.set(proxiedToString, proxyToStringFn.nativeToString);
+ Function.prototype.toString = proxiedToString;
+ }
+ proxyToStringFn.proxies.set(proxiedFn, nativeFn);
+}
+registerScriptlet(proxyToStringFn, {
+ name: 'proxy-tostring.fn',
+});
+
+/******************************************************************************/
+
export function proxyApplyFn(
target = '',
handler = '',
diff --git src/js/resources/replace-argument.js src/js/resources/replace-argument.js
index 783fac37abd1d..0c98217a44e02 100644
--- src/js/resources/replace-argument.js
+++ src/js/resources/replace-argument.js
@@ -109,7 +109,7 @@ export function trustedReplaceArgument(
}
const argBefore = getArg(context);
if ( extraArgs.condition !== undefined ) {
- if ( safe.RegExp_test.call(reCondition, argBefore) === false ) {
+ if ( safe.RegExp_test(reCondition, argBefore) === false ) {
return context.reflect();
}
}
diff --git src/js/resources/safe-self.js src/js/resources/safe-self.js
index 4a48fd8a119e9..19a06f9404916 100644
--- src/js/resources/safe-self.js
+++ src/js/resources/safe-self.js
@@ -35,8 +35,7 @@ export function safeSelf() {
const safe = {
'Array_from': Array.from,
'Error': self.Error,
- 'Function_toStringFn': self.Function.prototype.toString,
- 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
+ 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString),
'Math_floor': Math.floor,
'Math_max': Math.max,
'Math_min': Math.min,
@@ -49,7 +48,7 @@ export function safeSelf() {
'Object_hasOwn': Object.hasOwn.bind(Object),
'Object_toString': Object.prototype.toString,
'RegExp': self.RegExp,
- 'RegExp_test': self.RegExp.prototype.test,
+ 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test),
'RegExp_exec': self.RegExp.prototype.exec,
'Request_clone': self.Request.prototype.clone,
'String': self.String,
@@ -60,10 +59,8 @@ export function safeSelf() {
'removeEventListener': self.EventTarget.prototype.removeEventListener,
'fetch': self.fetch,
'JSON': self.JSON,
- 'JSON_parseFn': self.JSON.parse,
- 'JSON_stringifyFn': self.JSON.stringify,
- 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args),
- 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args),
+ 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON),
+ 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON),
'log': console.log.bind(console),
// Properties
logLevel: 0,
@@ -116,7 +113,7 @@ export function safeSelf() {
testPattern(details, haystack) {
if ( details.matchAll ) { return true; }
if ( details.re ) {
- return this.RegExp_test.call(details.re, haystack) === details.expect;
+ return this.RegExp_test(details.re, haystack) === details.expect;
}
return haystack.includes(details.pattern) === details.expect;
},
diff --git src/js/resources/scriptlets.js src/js/resources/scriptlets.js
index 6950bed588110..41da2b851caf9 100755
--- src/js/resources/scriptlets.js
+++ src/js/resources/scriptlets.js
@@ -36,9 +36,9 @@ import './prevent-fetch.js';
import './prevent-innerHTML.js';
import './prevent-navigation.js';
import './prevent-settimeout.js';
-import './prevent-xhr.js';
import './replace-argument.js';
import './spoof-css.js';
+import './vod.js';
import {
collateFetchArgumentsFn,
@@ -49,11 +49,15 @@ import {
onIdleFn,
parsePropertiesToMatchFn,
} from './utils.js';
-import { runAt, runAtHtmlElementFn } from './run-at.js';
+import {
+ runAt,
+ runAtHtmlElementFn,
+} from './run-at.js';
import { getAllCookiesFn } from './cookie.js';
import { getAllLocalStorageFn } from './localstorage.js';
import { matchesStackTraceFn } from './stack-trace.js';
+import { modifyXhrResponseFn } from './prevent-xhr.js';
import { proxyApplyFn } from './proxy-apply.js';
import { registeredScriptlets } from './base.js';
import { safeSelf } from './safe-self.js';
@@ -123,14 +127,14 @@ function replaceNodeTextFn(
const before = node.textContent;
if ( reIncludes ) {
reIncludes.lastIndex = 0;
- if ( safe.RegExp_test.call(reIncludes, before) === false ) { return true; }
+ if ( safe.RegExp_test(reIncludes, before) === false ) { return true; }
}
if ( reExcludes ) {
reExcludes.lastIndex = 0;
- if ( safe.RegExp_test.call(reExcludes, before) ) { return true; }
+ if ( safe.RegExp_test(reExcludes, before) ) { return true; }
}
rePattern.lastIndex = 0;
- if ( safe.RegExp_test.call(rePattern, before) === false ) { return true; }
+ if ( safe.RegExp_test(rePattern, before) === false ) { return true; }
rePattern.lastIndex = 0;
const after = pattern !== ''
? before.replace(rePattern, replacement)
@@ -984,6 +988,7 @@ builtinScriptlets.push({
name: 'xml-prune.js',
fn: xmlPrune,
dependencies: [
+ 'modify-xhr-response.fn',
'safe-self.fn',
],
});
@@ -1089,41 +1094,14 @@ function xmlPrune(
});
}
});
- self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, {
- apply: async (target, thisArg, args) => {
- if ( reUrl.test(urlFromArg(args[1])) === false ) {
- return Reflect.apply(target, thisArg, args);
- }
- thisArg.addEventListener('readystatechange', function() {
- if ( thisArg.readyState !== 4 ) { return; }
- const type = thisArg.responseType;
- if (
- type === 'document' ||
- type === '' && thisArg.responseXML instanceof XMLDocument
- ) {
- pruneFromDoc(thisArg.responseXML);
- const serializer = new XMLSerializer();
- const textout = serializer.serializeToString(thisArg.responseXML);
- Object.defineProperty(thisArg, 'responseText', { value: textout });
- if ( typeof thisArg.response === 'string' ) {
- Object.defineProperty(thisArg, 'response', { value: textout });
- }
- return;
- }
- if (
- type === 'text' ||
- type === '' && typeof thisArg.responseText === 'string'
- ) {
- const textin = thisArg.responseText;
- const textout = pruneFromText(textin);
- if ( textout === textin ) { return; }
- Object.defineProperty(thisArg, 'response', { value: textout });
- Object.defineProperty(thisArg, 'responseText', { value: textout });
- return;
- }
- });
- return Reflect.apply(target, thisArg, args);
+ modifyXhrResponseFn(urlPattern, (xhr, before) => {
+ if ( before instanceof XMLDocument ) {
+ return pruneFromDoc(before);
+ }
+ if ( typeof before === 'string' ) {
+ return pruneFromText(before);
}
+ return before;
});
}
@@ -1935,7 +1913,7 @@ function trustedSuppressNativeMethod(
}
}
if ( signatureArg.type === 'pattern' ) {
- if ( safe.RegExp_test.call(signatureArg.re, targetArg) === false ) {
+ if ( safe.RegExp_test(signatureArg.re, targetArg) === false ) {
return context.reflect();
}
}
--- /dev/null
+++ src/js/resources/vod.js
@@ -0,0 +1,175 @@
+/*******************************************************************************
+
+ uBlock Origin - a comprehensive, efficient content blocker
+ Copyright (C) 2026-present Raymond Hill
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+
+*/
+
+import { modifyXhrResponseFn } from './prevent-xhr.js';
+import { registerScriptlet } from './base.js';
+import { safeSelf } from './safe-self.js';
+
+export function mpegdashPrune(
+ selector = '',
+ propsToMatch = ''
+) {
+ if ( typeof selector !== 'string' ) { return; }
+ if ( selector === '' ) { return; }
+ const safe = safeSelf();
+ const logPrefix = safe.makeLogPrefix('mpegdash-prune', selector, propsToMatch);
+ const queryAll = (xmlDoc, selector) => {
+ if ( selector.startsWith('xpath:') === false ) {
+ return Array.from(xmlDoc.querySelectorAll(selector));
+ }
+ const xpr = xmlDoc.evaluate(
+ selector.slice(6),
+ xmlDoc,
+ null,
+ XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
+ null
+ );
+ const out = [];
+ for ( let i = 0; i < xpr.snapshotLength; i++ ) {
+ const node = xpr.snapshotItem(i);
+ out.push(node);
+ }
+ return out;
+ };
+ const rePTparse = /^PT(\d+D)?(\d+H)?(\d+M)?([\d.]+S)?$/;
+ const secondsPerDay = 24 * 60 * 60;
+ const secondsPerHour = 60 * 60;
+ const secondsPerMinute = 60;
+ const secondsFromPT = pt => {
+ const match = rePTparse.exec(pt);
+ if ( match === null ) { return; }
+ let seconds = 0;
+ if ( match[1] ) {
+ const d = parseFloat(match[1].slice(0, -1));
+ if ( isNaN(d) ) { return; }
+ seconds += d * secondsPerDay;
+ }
+ if ( match[2] ) {
+ const h = parseFloat(match[2].slice(0, -1));
+ if ( isNaN(h) ) { return; }
+ seconds += h * secondsPerHour;
+ }
+ if ( match[3] ) {
+ const m = parseFloat(match[3].slice(0, -1));
+ if ( isNaN(m) ) { return; }
+ seconds += m * secondsPerMinute;
+ }
+ if ( match[4] ) {
+ const s = parseFloat(match[4].slice(0, -1));
+ if ( isNaN(s) ) { return; }
+ seconds += s;
+ }
+ return seconds;
+ };
+ const ptFromSeconds = seconds => {
+ const parts = [ 'PT' ];
+ const d = Math.floor(seconds / secondsPerDay);
+ if ( d ) {
+ parts.push(`${d}D`);
+ seconds -= d * secondsPerDay;
+ }
+ const h = Math.floor(seconds / secondsPerHour);
+ if ( h ) {
+ parts.push(`${h}H`);
+ seconds -= h * secondsPerHour;
+ }
+ const m = Math.floor(seconds / secondsPerMinute);
+ if ( m ) {
+ parts.push(`${m}M`);
+ seconds -= m * secondsPerMinute;
+ }
+ parts.push(`${seconds}S`);
+ return parts.join('');
+ };
+ const fixTimeAttributes = xmlDoc => {
+ try {
+ const periods = queryAll(xmlDoc, 'MPD > Period');
+ if ( periods.length === 0 ) { return; }
+ let seconds = 0;
+ for ( const period of periods ) {
+ const startAttrBefore = period.getAttribute('start');
+ const durAttr = period.getAttribute('duration');
+ if ( startAttrBefore === null || durAttr === null ) { continue; }
+ const startAttrAfter = ptFromSeconds(seconds);
+ period.setAttribute('start', startAttrAfter);
+ if ( period.hasAttribute('id') ) {
+ const idAttr = period.getAttribute('id');
+ period.setAttribute('id', idAttr.replace(startAttrBefore, startAttrAfter));
+ }
+ seconds += secondsFromPT(durAttr);
+ }
+ const mpds = queryAll(xmlDoc, 'MPD[mediaPresentationDuration]');
+ if ( mpds.length !== 1 ) { return; }
+ mpds[0].setAttribute('mediaPresentationDuration', ptFromSeconds(seconds));
+ } catch {
+ }
+ };
+ const pruneFromDoc = xmlDoc => {
+ try {
+ if ( selector === '' ) {
+ const serializer = new XMLSerializer();
+ safe.uboLog(logPrefix, `Document is\n\t${serializer.serializeToString(xmlDoc)}`);
+ }
+ const items = queryAll(xmlDoc, selector);
+ if ( items.length === 0 ) { return xmlDoc; }
+ safe.uboLog(logPrefix, `Patching ${items.length} items`);
+ for ( const item of items ) {
+ if ( item.nodeType !== 1 ) { continue; }
+ item.setAttribute('duration', 'PT0S');
+ }
+ fixTimeAttributes(xmlDoc);
+ } catch(ex) {
+ safe.uboErr(logPrefix, `Error: ${ex}`);
+ }
+ return xmlDoc;
+ };
+ const pruneFromText = text => {
+ if ( (/^\s*</.test(text) && />\s*$/.test(text)) === false ) {
+ return text;
+ }
+ try {
+ const xmlParser = new DOMParser();
+ const xmlDoc = xmlParser.parseFromString(text, 'text/xml');
+ pruneFromDoc(xmlDoc);
+ const serializer = new XMLSerializer();
+ text = serializer.serializeToString(xmlDoc);
+ } catch {
+ }
+ return text;
+ };
+ modifyXhrResponseFn(propsToMatch, (xhr, before) => {
+ if ( before instanceof XMLDocument ) {
+ return pruneFromDoc(before);
+ }
+ if ( typeof before === 'string' ) {
+ return pruneFromText(before);
+ }
+ return before;
+ });
+}
+registerScriptlet(mpegdashPrune, {
+ name: 'mpegdash-prune.js',
+ dependencies: [
+ modifyXhrResponseFn,
+ safeSelf,
+ ],
+});
--- /dev/null
+++ src/web_accessible_resources/google-ima-dai.js
@@ -0,0 +1,630 @@
+// Repo: https://github.com/AdguardTeam/Scriptlets
+// Source: https://github.com/AdguardTeam/Scriptlets/blob/master/src/redirects/google-ima3-dai.ts
+// License: https://github.com/AdguardTeam/Scriptlets/blob/master/LICENSE (GPLv3)
+// Commit: https://github.com/AdguardTeam/Scriptlets/blob/eedd995c41/src/redirects/google-ima3-dai.ts
+/* eslint-disable */
+(function(source, args) {
+ const flag = "done";
+ const uniqueIdentifier = source.uniqueId + source.name + "_" + (Array.isArray(args) ? args.join("_") : "");
+ if (source.uniqueId) {
+ if (Window.prototype.toString[uniqueIdentifier] === flag) {
+ return;
+ }
+ }
+ function GoogleIma3Dai(source) {
+ var streamEventTypes = {
+ AD_BREAK_ENDED: "adBreakEnded",
+ AD_BREAK_STARTED: "adBreakStarted",
+ AD_PERIOD_ENDED: "adPeriodEnded",
+ AD_PERIOD_STARTED: "adPeriodStarted",
+ AD_PROGRESS: "adProgress",
+ CLICK: "click",
+ COMPLETE: "complete",
+ CUEPOINTS_CHANGED: "cuepointsChanged",
+ ERROR: "error",
+ FIRST_QUARTILE: "firstquartile",
+ HIDE_AD_UI: "hideAdUi",
+ LOADED: "loaded",
+ MIDPOINT: "midpoint",
+ PAUSED: "paused",
+ RESUMED: "resumed",
+ SHOW_AD_UI: "showAdUi",
+ SKIPPABLE_STATE_CHANGED: "skippableStateChanged",
+ SKIPPED: "skip",
+ STARTED: "started",
+ STREAM_INITIALIZED: "streamInitialized",
+ THIRD_QUARTILE: "thirdquartile",
+ VIDEO_CLICKED: "videoClicked"
+ };
+ var isRecord = function isRecord(value) {
+ return typeof value === "object" && value !== null;
+ };
+ var schedule = function schedule(callback) {
+ if (typeof requestAnimationFrame === "function") {
+ requestAnimationFrame(callback);
+ return;
+ }
+ setTimeout(callback, 0);
+ };
+ var toStringRecord = function toStringRecord(value) {
+ if (!isRecord(value)) {
+ return {};
+ }
+ var result = {};
+ var propertyNames = Object.keys(value);
+ for (var propertyIndex = 0; propertyIndex < propertyNames.length; propertyIndex += 1) {
+ var propertyName = propertyNames[propertyIndex];
+ result[propertyName] = String(value[propertyName]);
+ }
+ return result;
+ };
+ var getStringValue = function getStringValue(value) {
+ return typeof value === "string" && value.length > 0 ? value : null;
+ };
+ var initializeEventHandler = function initializeEventHandler(instance) {
+ instance.listeners = new Map;
+ };
+ var normalizeEventTypes = function normalizeEventTypes(type) {
+ if (typeof type === "string") {
+ return [ type ];
+ }
+ if (!Array.isArray(type)) {
+ return [];
+ }
+ var eventTypes = [];
+ for (var eventTypeIndex = 0; eventTypeIndex < type.length; eventTypeIndex += 1) {
+ var eventType = type[eventTypeIndex];
+ if (typeof eventType === "string") {
+ eventTypes.push(eventType);
+ }
+ }
+ return eventTypes;
+ };
+ var initializeStreamRequest = function initializeStreamRequest(instance, streamRequest) {
+ instance.adTagParameters = {};
+ instance.apiKey = null;
+ instance.authToken = null;
+ instance.format = "hls";
+ instance.networkCode = null;
+ instance.omidAccessModeRules = null;
+ instance.streamActivityMonitorId = null;
+ if (isRecord(streamRequest)) {
+ Object.assign(instance, streamRequest);
+ }
+ instance.adTagParameters = toStringRecord(instance.adTagParameters);
+ if (typeof instance.format !== "string" || instance.format.length === 0) {
+ instance.format = "hls";
+ }
+ };
+ var initializePodStreamRequest = function initializePodStreamRequest(instance, podStreamRequest) {
+ initializeStreamRequest(instance, podStreamRequest);
+ instance.customAssetKey = typeof instance.customAssetKey === "string" ? instance.customAssetKey : "";
+ };
+ var EventHandler = function EventHandler() {
+ initializeEventHandler(this);
+ };
+ EventHandler.prototype.addEventListener = function(type, listener) {
+ if (typeof listener !== "function") {
+ return;
+ }
+ var eventTypes = normalizeEventTypes(type);
+ for (var eventTypeIndex = 0; eventTypeIndex < eventTypes.length; eventTypeIndex += 1) {
+ var eventType = eventTypes[eventTypeIndex];
+ if (!this.listeners.has(eventType)) {
+ this.listeners.set(eventType, new Set);
+ }
+ var listeners = this.listeners.get(eventType);
+ if (listeners) {
+ listeners.add(listener);
+ }
+ }
+ };
+ EventHandler.prototype.removeEventListener = function(type, listener) {
+ if (typeof listener !== "function") {
+ return;
+ }
+ var eventTypes = normalizeEventTypes(type);
+ for (var eventTypeIndex = 0; eventTypeIndex < eventTypes.length; eventTypeIndex += 1) {
+ var listeners = this.listeners.get(eventTypes[eventTypeIndex]);
+ if (!listeners) {
+ continue;
+ }
+ listeners.delete(listener);
+ }
+ };
+ EventHandler.prototype.dispatchEvent = function(streamEvent) {
+ var listeners = this.listeners.get(streamEvent.type);
+ if (!listeners) {
+ return;
+ }
+ for (var _i = 0, _Array$from = Array.from(listeners); _i < _Array$from.length; _i++) {
+ var _listener = _Array$from[_i];
+ try {
+ _listener(streamEvent);
+ } catch (error) {
+ logMessage(source, error);
+ }
+ }
+ };
+ var StreamRequest = function StreamRequest(streamRequest) {
+ initializeStreamRequest(this, streamRequest);
+ };
+ var LiveStreamRequest = function LiveStreamRequest(liveStreamRequest) {
+ initializeStreamRequest(this, liveStreamRequest);
+ this.assetKey = typeof this.assetKey === "string" ? this.assetKey : "";
+ };
+ Object.setPrototypeOf(LiveStreamRequest.prototype, StreamRequest.prototype);
+ var PodStreamRequest = function PodStreamRequest(podStreamRequest) {
+ initializePodStreamRequest(this, podStreamRequest);
+ };
+ Object.setPrototypeOf(PodStreamRequest.prototype, StreamRequest.prototype);
+ var VideoStitcherLiveStreamRequest = function VideoStitcherLiveStreamRequest(videoStitcherLiveStreamRequest) {
+ initializePodStreamRequest(this, videoStitcherLiveStreamRequest);
+ this.liveStreamEventId = typeof this.liveStreamEventId === "string" ? this.liveStreamEventId : "";
+ this.oAuthToken = typeof this.oAuthToken === "string" ? this.oAuthToken : null;
+ this.projectNumber = typeof this.projectNumber === "string" ? this.projectNumber : null;
+ this.region = typeof this.region === "string" ? this.region : null;
+ this.videoStitcherSessionOptions = isRecord(this.videoStitcherSessionOptions) ? this.videoStitcherSessionOptions : null;
+ };
+ Object.setPrototypeOf(VideoStitcherLiveStreamRequest.prototype, PodStreamRequest.prototype);
+ var VideoStitcherVodStreamRequest = function VideoStitcherVodStreamRequest(videoStitcherVodStreamRequest) {
+ initializeStreamRequest(this, videoStitcherVodStreamRequest);
+ this.adTagUrl = typeof this.adTagUrl === "string" ? this.adTagUrl : "";
+ this.contentSourceUrl = typeof this.contentSourceUrl === "string" ? this.contentSourceUrl : "";
+ this.oAuthToken = typeof this.oAuthToken === "string" ? this.oAuthToken : null;
+ this.projectNumber = typeof this.projectNumber === "string" ? this.projectNumber : null;
+ this.region = typeof this.region === "string" ? this.region : null;
+ this.videoStitcherSessionOptions = isRecord(this.videoStitcherSessionOptions) ? this.videoStitcherSessionOptions : null;
+ this.vodConfigId = typeof this.vodConfigId === "string" ? this.vodConfigId : "";
+ };
+ Object.setPrototypeOf(VideoStitcherVodStreamRequest.prototype, StreamRequest.prototype);
+ var VODStreamRequest = function VODStreamRequest(vodStreamRequest) {
+ initializeStreamRequest(this, vodStreamRequest);
+ this.contentSourceId = typeof this.contentSourceId === "string" ? this.contentSourceId : "";
+ this.videoId = typeof this.videoId === "string" ? this.videoId : "";
+ };
+ Object.setPrototypeOf(VODStreamRequest.prototype, StreamRequest.prototype);
+ var StreamData = function StreamData(streamData) {
+ this.adPeriodData = null;
+ this.adProgressData = null;
+ this.cuepoints = [];
+ this.errorMessage = null;
+ this.manifestFormat = "HLS";
+ this.streamId = null;
+ this.subtitles = [];
+ this.url = "";
+ if (isRecord(streamData)) {
+ Object.assign(this, streamData);
+ }
+ };
+ var StreamEvent = function StreamEvent(type, streamData, ad) {
+ this.type = type;
+ this.streamData = streamData || new StreamData;
+ this.ad = ad || null;
+ };
+ StreamEvent.Type = streamEventTypes;
+ StreamEvent.prototype.getAd = function() {
+ return this.ad;
+ };
+ StreamEvent.prototype.getStreamData = function() {
+ return this.streamData;
+ };
+ var UiSettings = function UiSettings() {
+ this.locale = "";
+ };
+ UiSettings.prototype.getLocale = function() {
+ return this.locale;
+ };
+ UiSettings.prototype.setLocale = function(locale) {
+ this.locale = locale;
+ };
+ var daiSdkFeatureFlagsStorage = new WeakMap;
+ var getStoredDaiSdkFeatureFlags = function getStoredDaiSdkFeatureFlags(instance) {
+ var storedFeatureFlags = daiSdkFeatureFlagsStorage.get(instance);
+ if (storedFeatureFlags) {
+ return storedFeatureFlags;
+ }
+ var nextFeatureFlags = {};
+ daiSdkFeatureFlagsStorage.set(instance, nextFeatureFlags);
+ return nextFeatureFlags;
+ };
+ var DaiSdkSettingsContainer = function DaiSdkSettingsContainer() {
+ daiSdkFeatureFlagsStorage.set(this, {});
+ };
+ DaiSdkSettingsContainer.prototype.getFeatureFlags = function() {
+ return getStoredDaiSdkFeatureFlags(this);
+ };
+ DaiSdkSettingsContainer.prototype.setFeatureFlags = function(featureFlags) {
+ daiSdkFeatureFlagsStorage.set(this, Object.assign({}, featureFlags));
+ };
+ var normalizeStreamRequest = function normalizeStreamRequest(streamRequest) {
+ if (streamRequest instanceof StreamRequest) {
+ return streamRequest;
+ }
+ if (isRecord(streamRequest)) {
+ if (typeof streamRequest.liveStreamEventId === "string") {
+ return new VideoStitcherLiveStreamRequest(streamRequest);
+ }
+ if (typeof streamRequest.contentSourceUrl === "string" || typeof streamRequest.vodConfigId === "string" || typeof streamRequest.adTagUrl === "string") {
+ return new VideoStitcherVodStreamRequest(streamRequest);
+ }
+ if (typeof streamRequest.customAssetKey === "string") {
+ return new PodStreamRequest(streamRequest);
+ }
+ if (typeof streamRequest.assetKey === "string") {
+ return new LiveStreamRequest(streamRequest);
+ }
+ if (typeof streamRequest.contentSourceId === "string" || typeof streamRequest.videoId === "string") {
+ return new VODStreamRequest(streamRequest);
+ }
+ }
+ return new StreamRequest;
+ };
+ var hasLiveIdentifiers = function hasLiveIdentifiers(streamRequest) {
+ var liveStreamRequest = streamRequest;
+ return typeof liveStreamRequest.assetKey === "string" && liveStreamRequest.assetKey.length > 0;
+ };
+ var hasVideoStitcherLiveIdentifiers = function hasVideoStitcherLiveIdentifiers(streamRequest) {
+ var videoStitcherLiveStreamRequest = streamRequest;
+ return typeof videoStitcherLiveStreamRequest.liveStreamEventId === "string" && videoStitcherLiveStreamRequest.liveStreamEventId.length > 0;
+ };
+ var hasPodIdentifiers = function hasPodIdentifiers(streamRequest) {
+ var podStreamRequest = streamRequest;
+ return typeof podStreamRequest.networkCode === "string" && podStreamRequest.networkCode.length > 0 && typeof podStreamRequest.customAssetKey === "string" && podStreamRequest.customAssetKey.length > 0;
+ };
+ var hasVideoStitcherVodIdentifiers = function hasVideoStitcherVodIdentifiers(streamRequest) {
+ var videoStitcherVodStreamRequest = streamRequest;
+ var hasContentSourceUrl = typeof videoStitcherVodStreamRequest.contentSourceUrl === "string" && videoStitcherVodStreamRequest.contentSourceUrl.length > 0;
+ var hasVodConfigId = typeof videoStitcherVodStreamRequest.vodConfigId === "string" && videoStitcherVodStreamRequest.vodConfigId.length > 0;
+ return hasContentSourceUrl || hasVodConfigId;
+ };
+ var hasVodIdentifiers = function hasVodIdentifiers(streamRequest) {
+ var vodStreamRequest = streamRequest;
+ return typeof vodStreamRequest.contentSourceId === "string" && vodStreamRequest.contentSourceId.length > 0 && typeof vodStreamRequest.videoId === "string" && vodStreamRequest.videoId.length > 0;
+ };
+ var hasIdentifiers = function hasIdentifiers(streamRequest) {
+ return hasLiveIdentifiers(streamRequest) || hasPodIdentifiers(streamRequest) || hasVideoStitcherLiveIdentifiers(streamRequest) || hasVideoStitcherVodIdentifiers(streamRequest) || hasVodIdentifiers(streamRequest);
+ };
+ var getFallbackStreamId = function getFallbackStreamId(streamRequest) {
+ var liveStreamRequest = streamRequest;
+ var videoStitcherLiveStreamRequest = streamRequest;
+ var videoStitcherVodStreamRequest = streamRequest;
+ var vodStreamRequest = streamRequest;
+ if (typeof videoStitcherVodStreamRequest.vodConfigId === "string" && videoStitcherVodStreamRequest.vodConfigId.length > 0) {
+ return `mock-video-stitcher-vod-${videoStitcherVodStreamRequest.vodConfigId}`;
+ }
+ if (typeof videoStitcherVodStreamRequest.contentSourceUrl === "string" && videoStitcherVodStreamRequest.contentSourceUrl.length > 0) {
+ return "mock-video-stitcher-vod";
+ }
+ if (typeof videoStitcherLiveStreamRequest.liveStreamEventId === "string" && videoStitcherLiveStreamRequest.liveStreamEventId.length > 0) {
+ return `mock-video-stitcher-live-${videoStitcherLiveStreamRequest.liveStreamEventId}`;
+ }
+ if (typeof liveStreamRequest.assetKey === "string" && liveStreamRequest.assetKey.length > 0) {
+ return `mock-live-${liveStreamRequest.assetKey}`;
+ }
+ if (typeof vodStreamRequest.videoId === "string" && vodStreamRequest.videoId.length > 0) {
+ return `mock-vod-${vodStreamRequest.videoId}`;
+ }
+ return "mock-stream";
+ };
+ var getDefaultManifestFormat = function getDefaultManifestFormat(streamRequest) {
+ return typeof streamRequest.format === "string" && streamRequest.format.toLowerCase() === "dash" ? "DASH" : "HLS";
+ };
+ var createStreamData = function createStreamData(streamRequest, cuepoints, errorMessage, streamDataOverrides) {
+ var streamData = new StreamData({
+ cuepoints: cuepoints.slice(),
+ errorMessage: errorMessage,
+ manifestFormat: getDefaultManifestFormat(streamRequest),
+ streamId: getFallbackStreamId(streamRequest),
+ url: ""
+ });
+ if (isRecord(streamDataOverrides)) {
+ Object.assign(streamData, streamDataOverrides);
+ }
+ return streamData;
+ };
+ var appendRequestParameters = function appendRequestParameters(requestUrl, streamRequest) {
+ var parameterNames = Object.keys(streamRequest.adTagParameters);
+ for (var parameterIndex = 0; parameterIndex < parameterNames.length; parameterIndex += 1) {
+ var parameterName = parameterNames[parameterIndex];
+ requestUrl.searchParams.set(parameterName, streamRequest.adTagParameters[parameterName]);
+ }
+ if (streamRequest.apiKey) {
+ requestUrl.searchParams.set("api-key", streamRequest.apiKey);
+ }
+ if (streamRequest.authToken) {
+ requestUrl.searchParams.set("auth-token", streamRequest.authToken);
+ }
+ if (streamRequest.streamActivityMonitorId) {
+ requestUrl.searchParams.set("dai-sam-id", streamRequest.streamActivityMonitorId);
+ }
+ };
+ var buildLiveRequestUrl = function buildLiveRequestUrl(streamRequest, hostName) {
+ var requestUrl = new URL(`${hostName}/ssai/event/${streamRequest.assetKey}/streams`);
+ appendRequestParameters(requestUrl, streamRequest);
+ return requestUrl.toString();
+ };
+ var buildPodRequestUrl = function buildPodRequestUrl(streamRequest, hostName) {
+ var requestUrl = new URL(`${hostName}/ssai/pods/api/v1/network/${streamRequest.networkCode}` + `/custom_asset/${streamRequest.customAssetKey}/stream`);
+ var manifestType = streamRequest.format.toLowerCase() === "dash" ? "dash" : "hls";
+ appendRequestParameters(requestUrl, streamRequest);
+ requestUrl.searchParams.set("manifest-type", manifestType);
+ return requestUrl.toString();
+ };
+ var buildVodRequestUrl = function buildVodRequestUrl(streamRequest, hostName) {
+ var requestFormat = streamRequest.format.toLowerCase() === "dash" ? "dash" : "hls";
+ var requestUrl = new URL(`${hostName}/ondemand/${requestFormat}/content/${streamRequest.contentSourceId}` + `/vid/${streamRequest.videoId}/streams`);
+ appendRequestParameters(requestUrl, streamRequest);
+ return requestUrl.toString();
+ };
+ var MAIN_HOST_NAME = "https://dai.google.com";
+ var FALLBACK_HOST_NAME = "https://pubads.g.doubleclick.net";
+ var getStreamRequestUrls = function getStreamRequestUrls(streamRequest) {
+ if (hasPodIdentifiers(streamRequest)) {
+ return [ buildPodRequestUrl(streamRequest, MAIN_HOST_NAME), buildPodRequestUrl(streamRequest, FALLBACK_HOST_NAME) ];
+ }
+ if (hasLiveIdentifiers(streamRequest)) {
+ return [ buildLiveRequestUrl(streamRequest, MAIN_HOST_NAME), buildLiveRequestUrl(streamRequest, FALLBACK_HOST_NAME) ];
+ }
+ if (hasVodIdentifiers(streamRequest)) {
+ return [ buildVodRequestUrl(streamRequest, MAIN_HOST_NAME), buildVodRequestUrl(streamRequest, FALLBACK_HOST_NAME) ];
+ }
+ return [];
+ };
+ var readFetchResponseData = async function readFetchResponseData(response) {
+ var typedResponse = response;
+ if (typedResponse && typedResponse.ok === false) {
+ throw new Error(`Stream initialization failed with status ${String(typedResponse.status || 0)}`);
+ }
+ if (typedResponse && typeof typedResponse.json === "function") {
+ var jsonResponse = await typedResponse.json();
+ return isRecord(jsonResponse) ? jsonResponse : {};
+ }
+ return isRecord(response) ? response : {};
+ };
+ var getResponseErrorMessage = function getResponseErrorMessage(responseData) {
+ return getStringValue(responseData.errorMessage) || getStringValue(responseData.error_message);
+ };
+ var createStreamDataFromResponse = function createStreamDataFromResponse(streamRequest, cuepoints, responseData) {
+ var podManifestUrl = getStringValue(responseData.pod_manifest_url) || getStringValue(responseData.podManifestUrl) || "";
+ var responseStreamId = getStringValue(responseData.stream_id) || getStringValue(responseData.streamId);
+ var streamUrl = getStringValue(responseData.stream_manifest) || getStringValue(responseData.streamUrl) || podManifestUrl || "";
+ var responseErrorMessage = getResponseErrorMessage(responseData);
+ var hasInitializedStream = streamUrl.length > 0 || responseStreamId !== null && responseStreamId.length > 0;
+ var errorMessage = responseErrorMessage || (hasInitializedStream ? null : "Stream initialization response missing stream URL");
+ var manifestFormat = getStringValue(responseData.manifest_format) || getStringValue(responseData.manifestFormat) || getDefaultManifestFormat(streamRequest);
+ var streamId = responseStreamId || getFallbackStreamId(streamRequest);
+ var subtitles = Array.isArray(responseData.subtitles) ? responseData.subtitles : [];
+ return createStreamData(streamRequest, cuepoints, errorMessage, {
+ manifestFormat: manifestFormat,
+ podManifestUrl: podManifestUrl,
+ pod_manifest_url: podManifestUrl,
+ streamId: streamId,
+ subtitles: subtitles,
+ url: streamUrl
+ });
+ };
+ var getErrorMessage = function getErrorMessage(error) {
+ if (isRecord(error) && typeof error.message === "string" && error.message.length > 0) {
+ return error.message;
+ }
+ return "Stream initialization failed";
+ };
+ var hideAdUiElement = function hideAdUiElement(streamManager) {
+ if (!streamManager.adUiElement) {
+ return;
+ }
+ streamManager.adUiElement.style.display = "none";
+ };
+ var showVideoControls = function showVideoControls(streamManager) {
+ if (!streamManager.videoElement || streamManager.videoElement.controls) {
+ return;
+ }
+ streamManager.videoElement.controls = true;
+ };
+ var handleContentLoaded = function handleContentLoaded(streamManager) {
+ hideAdUiElement(streamManager);
+ showVideoControls(streamManager);
+ };
+ var isContentLoadedEventType = function isContentLoadedEventType(eventType) {
+ return eventType === StreamEvent.Type.LOADED || eventType === StreamEvent.Type.STREAM_INITIALIZED;
+ };
+ var StreamManager = function StreamManager(videoElement, adUiElement, uiSettings) {
+ initializeEventHandler(this);
+ this.videoElement = videoElement || null;
+ this.adUiElement = adUiElement || null;
+ this.uiSettings = uiSettings || new UiSettings;
+ this.clickElement = adUiElement || null;
+ this.streamData = new StreamData;
+ this.streamMonitor = {};
+ this.streamRequest = null;
+ this.cuepoints = [];
+ this.lastMetadata = null;
+ this.lastTimedMetadata = null;
+ };
+ Object.setPrototypeOf(StreamManager.prototype, EventHandler.prototype);
+ StreamManager.prototype.contentTimeForStreamTime = function(streamTime) {
+ return typeof streamTime === "number" ? streamTime : 0;
+ };
+ StreamManager.prototype.destroy = function() {
+ this.reset();
+ };
+ StreamManager.prototype.focus = function() {
+ var clickElement = this.clickElement;
+ if (!clickElement || typeof clickElement.focus !== "function") {
+ return;
+ }
+ try {
+ clickElement.focus();
+ } catch (error) {
+ logMessage(source, error);
+ }
+ };
+ StreamManager.prototype.getAdSkippableState = function() {
+ return true;
+ };
+ StreamManager.prototype.getStreamData = function() {
+ return this.streamData;
+ };
+ StreamManager.prototype.loadStreamMetadata = function() {
+ handleContentLoaded(this);
+ this.dispatchEvent(new StreamEvent(StreamEvent.Type.LOADED, this.streamData));
+ };
+ StreamManager.prototype.onTimedMetadata = function(metadata) {
+ this.lastTimedMetadata = metadata;
+ };
+ StreamManager.prototype.previousCuePointForStreamTime = function(streamTime) {
+ var previousCuePoint = null;
+ for (var cuepointIndex = 0; cuepointIndex < this.cuepoints.length; cuepointIndex += 1) {
+ var cuepoint = this.cuepoints[cuepointIndex];
+ if (typeof cuepoint.start !== "number") {
+ continue;
+ }
+ if (cuepoint.start <= streamTime) {
+ previousCuePoint = cuepoint;
+ }
+ }
+ return previousCuePoint;
+ };
+ StreamManager.prototype.processMetadata = function(type, data, timestamp) {
+ this.lastMetadata = {
+ data: data,
+ timestamp: timestamp,
+ type: type
+ };
+ };
+ StreamManager.prototype.replaceAdTagParameters = function(adTagParameters) {
+ if (!this.streamRequest) {
+ this.streamRequest = new StreamRequest;
+ }
+ this.streamRequest.adTagParameters = toStringRecord(adTagParameters);
+ };
+ StreamManager.prototype.requestStream = function(streamRequest) {
+ var _this = this;
+ var normalizedRequest = normalizeStreamRequest(streamRequest);
+ this.streamRequest = normalizedRequest;
+ var dispatchStreamEvent = function dispatchStreamEvent(eventType, streamData) {
+ _this.streamData = streamData;
+ if (isContentLoadedEventType(eventType)) {
+ handleContentLoaded(_this);
+ }
+ schedule((function() {
+ _this.dispatchEvent(new StreamEvent(StreamEvent.Type.STREAM_INITIALIZED, streamData));
+ _this.dispatchEvent(new StreamEvent(eventType, streamData));
+ }));
+ };
+ if (!hasIdentifiers(normalizedRequest)) {
+ dispatchStreamEvent(StreamEvent.Type.ERROR, createStreamData(normalizedRequest, this.cuepoints, "Missing stream request identifiers"));
+ return;
+ }
+ var requestUrls = getStreamRequestUrls(normalizedRequest);
+ if (requestUrls.length > 0) {
+ var activeRequest = normalizedRequest;
+ var _fetchStreamData = async function fetchStreamData(requestIndex) {
+ try {
+ var fetchResponse = await fetch(requestUrls[requestIndex], {
+ method: "POST",
+ credentials: "include"
+ });
+ var responseData = await readFetchResponseData(fetchResponse);
+ if (_this.streamRequest !== activeRequest) {
+ return;
+ }
+ var _streamData = createStreamDataFromResponse(activeRequest, _this.cuepoints, responseData);
+ var eventType = _streamData.errorMessage ? StreamEvent.Type.ERROR : StreamEvent.Type.LOADED;
+ dispatchStreamEvent(eventType, _streamData);
+ } catch (error) {
+ if (_this.streamRequest !== activeRequest) {
+ return;
+ }
+ if (requestIndex + 1 < requestUrls.length) {
+ await _fetchStreamData(requestIndex + 1);
+ return;
+ }
+ dispatchStreamEvent(StreamEvent.Type.ERROR, createStreamData(activeRequest, _this.cuepoints, getErrorMessage(error)));
+ }
+ };
+ _fetchStreamData(0);
+ return;
+ }
+ dispatchStreamEvent(StreamEvent.Type.LOADED, createStreamData(normalizedRequest, this.cuepoints, null));
+ };
+ StreamManager.prototype.reset = function() {
+ this.cuepoints = [];
+ this.lastMetadata = null;
+ this.lastTimedMetadata = null;
+ this.streamData = new StreamData;
+ this.streamRequest = null;
+ };
+ StreamManager.prototype.setClickElement = function(clickElement) {
+ if (this.adUiElement) {
+ return;
+ }
+ this.clickElement = clickElement;
+ };
+ StreamManager.prototype.streamTimeForContentTime = function(contentTime) {
+ return typeof contentTime === "number" ? contentTime : 0;
+ };
+ var api = {
+ DaiSdkSettings: new DaiSdkSettingsContainer,
+ LiveStreamRequest: LiveStreamRequest,
+ PodStreamRequest: PodStreamRequest,
+ StreamData: StreamData,
+ StreamEvent: StreamEvent,
+ StreamManager: StreamManager,
+ StreamRequest: StreamRequest,
+ UiSettings: UiSettings,
+ VideoStitcherLiveStreamRequest: VideoStitcherLiveStreamRequest,
+ VideoStitcherVodStreamRequest: VideoStitcherVodStreamRequest,
+ VODStreamRequest: VODStreamRequest
+ };
+ var globalWindow = window;
+ var googleNamespace = isRecord(globalWindow.google) ? globalWindow.google : {};
+ if (!isRecord(globalWindow.google)) {
+ globalWindow.google = googleNamespace;
+ }
+ var imaNamespace = isRecord(googleNamespace.ima) ? googleNamespace.ima : {};
+ googleNamespace.ima = imaNamespace;
+ var daiNamespace = isRecord(imaNamespace.dai) ? imaNamespace.dai : {};
+ imaNamespace.dai = daiNamespace;
+ var apiNamespace = isRecord(daiNamespace.api) ? daiNamespace.api : {};
+ daiNamespace.api = apiNamespace;
+ Object.assign(apiNamespace, api);
+ hit(source);
+ }
+ function hit(e) {
+ if (e.verbose) {
+ try {
+ var n = console.trace.bind(console), i = "[AdGuard] ";
+ "corelibs" === e.engine ? i += e.ruleText : (e.domainName && (i += `${e.domainName}`),
+ e.args ? i += `#%#//scriptlet('${e.name}', '${e.args.join("', '")}')` : i += `#%#//scriptlet('${e.name}')`),
+ n && n(i);
+ } catch (e) {}
+ "function" == typeof window.__debug && window.__debug(e);
+ }
+ }
+ function logMessage(e, o) {
+ var r = arguments.length > 2 && void 0 !== arguments[2] && arguments[2], a = !(arguments.length > 3 && void 0 !== arguments[3]) || arguments[3], {name: n, verbose: g} = e;
+ if (r || g) {
+ var i = console.log;
+ a ? i(`${n}: ${o}`) : Array.isArray(o) ? i(`${n}:`, ...o) : i(`${n}:`, o);
+ }
+ }
+ const updatedArgs = args ? [].concat(source).concat(args) : [ source ];
+ try {
+ GoogleIma3Dai.apply(this, updatedArgs);
+ if (source.uniqueId) {
+ Object.defineProperty(Window.prototype.toString, uniqueIdentifier, {
+ value: flag,
+ enumerable: false,
+ writable: false,
+ configurable: false
+ });
+ }
+ } catch (e) {
+ console.log(e);
+ }
+})({
+ name: "google-ima3-dai",
+ args: []
+}, []);
Verdictpass Risklow SummaryThe diff is a set of upstream-style refactors (safe-self binding cleanup, Findings
|
This PR was automatically created by a GitHub Action triggered by a cron schedule. Please review the changes and merge if appropriate.