Fix Trusted Types violation in manifest interceptor injection, which fixes data not showing for YouTube DRM
This commit is contained in:
parent
889a4c63f3
commit
6e22837047
181
mv2/inject.js
181
mv2/inject.js
@ -70,108 +70,129 @@ function safeHeaderShellEscape(str) {
|
|||||||
|
|
||||||
// Intercep network to find manifest
|
// Intercep network to find manifest
|
||||||
function injectManifestInterceptor() {
|
function injectManifestInterceptor() {
|
||||||
const script = document.createElement("script");
|
// Execute the interceptor code directly instead of injecting a script
|
||||||
script.textContent = `
|
(function () {
|
||||||
(function() {
|
function isProbablyManifest(text = "", contentType = "") {
|
||||||
function isProbablyManifest(text = "", contentType = "") {
|
const lowerCT = contentType?.toLowerCase() ?? "";
|
||||||
const lowerCT = contentType?.toLowerCase() ?? "";
|
const sample = text.slice(0, 2000);
|
||||||
const sample = text.slice(0, 2000);
|
|
||||||
|
|
||||||
const isHLSMime = lowerCT.includes("mpegurl");
|
const isHLSMime = lowerCT.includes("mpegurl");
|
||||||
const isDASHMime = lowerCT.includes("dash+xml");
|
const isDASHMime = lowerCT.includes("dash+xml");
|
||||||
const isSmoothMime = lowerCT.includes("sstr+xml");
|
const isSmoothMime = lowerCT.includes("sstr+xml");
|
||||||
|
|
||||||
const isHLSKeyword = sample.includes("#EXTM3U") || sample.includes("#EXT-X-STREAM-INF");
|
const isHLSKeyword = sample.includes("#EXTM3U") || sample.includes("#EXT-X-STREAM-INF");
|
||||||
const isDASHKeyword = sample.includes("<MPD") || sample.includes("<AdaptationSet");
|
const isDASHKeyword = sample.includes("<MPD") || sample.includes("<AdaptationSet");
|
||||||
const isSmoothKeyword = sample.includes("<SmoothStreamingMedia");
|
const isSmoothKeyword = sample.includes("<SmoothStreamingMedia");
|
||||||
const isJsonManifest = sample.includes('"playlist"') && sample.includes('"segments"');
|
const isJsonManifest = sample.includes('"playlist"') && sample.includes('"segments"');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isHLSMime || isDASHMime || isSmoothMime ||
|
isHLSMime ||
|
||||||
isHLSKeyword || isDASHKeyword || isSmoothKeyword || isJsonManifest
|
isDASHMime ||
|
||||||
);
|
isSmoothMime ||
|
||||||
}
|
isHLSKeyword ||
|
||||||
|
isDASHKeyword ||
|
||||||
|
isSmoothKeyword ||
|
||||||
|
isJsonManifest
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const originalFetch = window.fetch;
|
const originalFetch = window.fetch;
|
||||||
window.fetch = async function(input, init) {
|
window.fetch = async function (input, init) {
|
||||||
const response = await originalFetch.apply(this, arguments);
|
const response = await originalFetch.apply(this, arguments);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const clone = response.clone();
|
const clone = response.clone();
|
||||||
const contentType = clone.headers.get("content-type") || "";
|
const contentType = clone.headers.get("content-type") || "";
|
||||||
const text = await clone.text();
|
const text = await clone.text();
|
||||||
|
|
||||||
const url = typeof input === "string" ? input : input.url;
|
const url = typeof input === "string" ? input : input.url;
|
||||||
|
|
||||||
if (isProbablyManifest(text, contentType)) {
|
if (isProbablyManifest(text, contentType)) {
|
||||||
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
||||||
console.log("[Manifest][fetch]", url, contentType);
|
console.log("[Manifest][fetch]", url, contentType);
|
||||||
|
|
||||||
const headersObj = {};
|
const headersObj = {};
|
||||||
clone.headers.forEach((value, key) => {
|
clone.headers.forEach((value, key) => {
|
||||||
headersObj[key] = value;
|
headersObj[key] = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const headerFlags = Object.entries(headersObj)
|
const headerFlags = Object.entries(headersObj)
|
||||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
.map(
|
||||||
.join(" ");
|
([key, val]) =>
|
||||||
|
'--add-headers "' +
|
||||||
|
safeHeaderShellEscape(key) +
|
||||||
|
": " +
|
||||||
|
safeHeaderShellEscape(val) +
|
||||||
|
'"'
|
||||||
|
)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
window.postMessage({
|
window.postMessage(
|
||||||
|
{
|
||||||
type: "__MANIFEST_HEADERS__",
|
type: "__MANIFEST_HEADERS__",
|
||||||
url,
|
url,
|
||||||
headers: headerFlags
|
headers: headerFlags,
|
||||||
}, "*");
|
},
|
||||||
}
|
"*"
|
||||||
} catch (e) {}
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||||
const originalXHRSend = XMLHttpRequest.prototype.send;
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
||||||
|
|
||||||
XMLHttpRequest.prototype.open = function(method, url) {
|
XMLHttpRequest.prototype.open = function (method, url) {
|
||||||
this.__url = url;
|
this.__url = url;
|
||||||
return originalXHROpen.apply(this, arguments);
|
return originalXHROpen.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
XMLHttpRequest.prototype.send = function(body) {
|
XMLHttpRequest.prototype.send = function (body) {
|
||||||
this.addEventListener("load", function () {
|
this.addEventListener("load", function () {
|
||||||
try {
|
try {
|
||||||
const contentType = this.getResponseHeader("content-type") || "";
|
const contentType = this.getResponseHeader("content-type") || "";
|
||||||
const text = this.responseText;
|
const text = this.responseText;
|
||||||
|
|
||||||
if (isProbablyManifest(text, contentType)) {
|
if (isProbablyManifest(text, contentType)) {
|
||||||
window.postMessage({ type: "__MANIFEST_URL__", data: this.__url }, "*");
|
window.postMessage({ type: "__MANIFEST_URL__", data: this.__url }, "*");
|
||||||
console.log("[Manifest][xhr]", this.__url, contentType);
|
console.log("[Manifest][xhr]", this.__url, contentType);
|
||||||
|
|
||||||
const xhrHeaders = {};
|
const xhrHeaders = {};
|
||||||
const rawHeaders = this.getAllResponseHeaders().trim().split(/\\r?\\n/);
|
const rawHeaders = this.getAllResponseHeaders().trim().split(/\r?\n/);
|
||||||
rawHeaders.forEach(line => {
|
rawHeaders.forEach((line) => {
|
||||||
const parts = line.split(": ");
|
const parts = line.split(": ");
|
||||||
if (parts.length === 2) {
|
if (parts.length === 2) {
|
||||||
xhrHeaders[parts[0]] = parts[1];
|
xhrHeaders[parts[0]] = parts[1];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const headerFlags = Object.entries(xhrHeaders)
|
const headerFlags = Object.entries(xhrHeaders)
|
||||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
.map(
|
||||||
.join(" ");
|
([key, val]) =>
|
||||||
|
'--add-headers "' +
|
||||||
|
safeHeaderShellEscape(key) +
|
||||||
|
": " +
|
||||||
|
safeHeaderShellEscape(val) +
|
||||||
|
'"'
|
||||||
|
)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
window.postMessage({
|
window.postMessage(
|
||||||
|
{
|
||||||
type: "__MANIFEST_HEADERS__",
|
type: "__MANIFEST_HEADERS__",
|
||||||
url: this.__url,
|
url: this.__url,
|
||||||
headers: headerFlags
|
headers: headerFlags,
|
||||||
}, "*");
|
},
|
||||||
}
|
"*"
|
||||||
} catch (e) {}
|
);
|
||||||
});
|
}
|
||||||
return originalXHRSend.apply(this, arguments);
|
} catch (e) {}
|
||||||
};
|
});
|
||||||
})();
|
return originalXHRSend.apply(this, arguments);
|
||||||
`;
|
};
|
||||||
document.documentElement.appendChild(script);
|
})();
|
||||||
script.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
injectManifestInterceptor();
|
injectManifestInterceptor();
|
||||||
|
181
src/inject.js
181
src/inject.js
@ -70,108 +70,129 @@ function safeHeaderShellEscape(str) {
|
|||||||
|
|
||||||
// Intercep network to find manifest
|
// Intercep network to find manifest
|
||||||
function injectManifestInterceptor() {
|
function injectManifestInterceptor() {
|
||||||
const script = document.createElement("script");
|
// Execute the interceptor code directly instead of injecting a script
|
||||||
script.textContent = `
|
(function () {
|
||||||
(function() {
|
function isProbablyManifest(text = "", contentType = "") {
|
||||||
function isProbablyManifest(text = "", contentType = "") {
|
const lowerCT = contentType?.toLowerCase() ?? "";
|
||||||
const lowerCT = contentType?.toLowerCase() ?? "";
|
const sample = text.slice(0, 2000);
|
||||||
const sample = text.slice(0, 2000);
|
|
||||||
|
|
||||||
const isHLSMime = lowerCT.includes("mpegurl");
|
const isHLSMime = lowerCT.includes("mpegurl");
|
||||||
const isDASHMime = lowerCT.includes("dash+xml");
|
const isDASHMime = lowerCT.includes("dash+xml");
|
||||||
const isSmoothMime = lowerCT.includes("sstr+xml");
|
const isSmoothMime = lowerCT.includes("sstr+xml");
|
||||||
|
|
||||||
const isHLSKeyword = sample.includes("#EXTM3U") || sample.includes("#EXT-X-STREAM-INF");
|
const isHLSKeyword = sample.includes("#EXTM3U") || sample.includes("#EXT-X-STREAM-INF");
|
||||||
const isDASHKeyword = sample.includes("<MPD") || sample.includes("<AdaptationSet");
|
const isDASHKeyword = sample.includes("<MPD") || sample.includes("<AdaptationSet");
|
||||||
const isSmoothKeyword = sample.includes("<SmoothStreamingMedia");
|
const isSmoothKeyword = sample.includes("<SmoothStreamingMedia");
|
||||||
const isJsonManifest = sample.includes('"playlist"') && sample.includes('"segments"');
|
const isJsonManifest = sample.includes('"playlist"') && sample.includes('"segments"');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isHLSMime || isDASHMime || isSmoothMime ||
|
isHLSMime ||
|
||||||
isHLSKeyword || isDASHKeyword || isSmoothKeyword || isJsonManifest
|
isDASHMime ||
|
||||||
);
|
isSmoothMime ||
|
||||||
}
|
isHLSKeyword ||
|
||||||
|
isDASHKeyword ||
|
||||||
|
isSmoothKeyword ||
|
||||||
|
isJsonManifest
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const originalFetch = window.fetch;
|
const originalFetch = window.fetch;
|
||||||
window.fetch = async function(input, init) {
|
window.fetch = async function (input, init) {
|
||||||
const response = await originalFetch.apply(this, arguments);
|
const response = await originalFetch.apply(this, arguments);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const clone = response.clone();
|
const clone = response.clone();
|
||||||
const contentType = clone.headers.get("content-type") || "";
|
const contentType = clone.headers.get("content-type") || "";
|
||||||
const text = await clone.text();
|
const text = await clone.text();
|
||||||
|
|
||||||
const url = typeof input === "string" ? input : input.url;
|
const url = typeof input === "string" ? input : input.url;
|
||||||
|
|
||||||
if (isProbablyManifest(text, contentType)) {
|
if (isProbablyManifest(text, contentType)) {
|
||||||
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
||||||
console.log("[Manifest][fetch]", url, contentType);
|
console.log("[Manifest][fetch]", url, contentType);
|
||||||
|
|
||||||
const headersObj = {};
|
const headersObj = {};
|
||||||
clone.headers.forEach((value, key) => {
|
clone.headers.forEach((value, key) => {
|
||||||
headersObj[key] = value;
|
headersObj[key] = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const headerFlags = Object.entries(headersObj)
|
const headerFlags = Object.entries(headersObj)
|
||||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
.map(
|
||||||
.join(" ");
|
([key, val]) =>
|
||||||
|
'--add-headers "' +
|
||||||
|
safeHeaderShellEscape(key) +
|
||||||
|
": " +
|
||||||
|
safeHeaderShellEscape(val) +
|
||||||
|
'"'
|
||||||
|
)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
window.postMessage({
|
window.postMessage(
|
||||||
|
{
|
||||||
type: "__MANIFEST_HEADERS__",
|
type: "__MANIFEST_HEADERS__",
|
||||||
url,
|
url,
|
||||||
headers: headerFlags
|
headers: headerFlags,
|
||||||
}, "*");
|
},
|
||||||
}
|
"*"
|
||||||
} catch (e) {}
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||||
const originalXHRSend = XMLHttpRequest.prototype.send;
|
const originalXHRSend = XMLHttpRequest.prototype.send;
|
||||||
|
|
||||||
XMLHttpRequest.prototype.open = function(method, url) {
|
XMLHttpRequest.prototype.open = function (method, url) {
|
||||||
this.__url = url;
|
this.__url = url;
|
||||||
return originalXHROpen.apply(this, arguments);
|
return originalXHROpen.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
XMLHttpRequest.prototype.send = function(body) {
|
XMLHttpRequest.prototype.send = function (body) {
|
||||||
this.addEventListener("load", function () {
|
this.addEventListener("load", function () {
|
||||||
try {
|
try {
|
||||||
const contentType = this.getResponseHeader("content-type") || "";
|
const contentType = this.getResponseHeader("content-type") || "";
|
||||||
const text = this.responseText;
|
const text = this.responseText;
|
||||||
|
|
||||||
if (isProbablyManifest(text, contentType)) {
|
if (isProbablyManifest(text, contentType)) {
|
||||||
window.postMessage({ type: "__MANIFEST_URL__", data: this.__url }, "*");
|
window.postMessage({ type: "__MANIFEST_URL__", data: this.__url }, "*");
|
||||||
console.log("[Manifest][xhr]", this.__url, contentType);
|
console.log("[Manifest][xhr]", this.__url, contentType);
|
||||||
|
|
||||||
const xhrHeaders = {};
|
const xhrHeaders = {};
|
||||||
const rawHeaders = this.getAllResponseHeaders().trim().split(/\\r?\\n/);
|
const rawHeaders = this.getAllResponseHeaders().trim().split(/\r?\n/);
|
||||||
rawHeaders.forEach(line => {
|
rawHeaders.forEach((line) => {
|
||||||
const parts = line.split(": ");
|
const parts = line.split(": ");
|
||||||
if (parts.length === 2) {
|
if (parts.length === 2) {
|
||||||
xhrHeaders[parts[0]] = parts[1];
|
xhrHeaders[parts[0]] = parts[1];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const headerFlags = Object.entries(xhrHeaders)
|
const headerFlags = Object.entries(xhrHeaders)
|
||||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
.map(
|
||||||
.join(" ");
|
([key, val]) =>
|
||||||
|
'--add-headers "' +
|
||||||
|
safeHeaderShellEscape(key) +
|
||||||
|
": " +
|
||||||
|
safeHeaderShellEscape(val) +
|
||||||
|
'"'
|
||||||
|
)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
window.postMessage({
|
window.postMessage(
|
||||||
|
{
|
||||||
type: "__MANIFEST_HEADERS__",
|
type: "__MANIFEST_HEADERS__",
|
||||||
url: this.__url,
|
url: this.__url,
|
||||||
headers: headerFlags
|
headers: headerFlags,
|
||||||
}, "*");
|
},
|
||||||
}
|
"*"
|
||||||
} catch (e) {}
|
);
|
||||||
});
|
}
|
||||||
return originalXHRSend.apply(this, arguments);
|
} catch (e) {}
|
||||||
};
|
});
|
||||||
})();
|
return originalXHRSend.apply(this, arguments);
|
||||||
`;
|
};
|
||||||
document.documentElement.appendChild(script);
|
})();
|
||||||
script.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
injectManifestInterceptor();
|
injectManifestInterceptor();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user