This repository has been archived on 2022-10-14. You can view files and clone it, but cannot push or open issues/pull-requests.
melonybot/resources/metastream-extension-0.4.0_0/first.js

151 lines
5.3 KiB
JavaScript

//
// The first script to be run on every page as to capture media elements
// when they're created.
//
// Has to be run before anything else is executed in the document.
// Declaring the script in the manifest, as opposed to using
// chrome.tabs.executeScript, seems to be the only way to achieve this from
// my own testing.
// https://bugs.chromium.org/p/chromium/issues/detail?id=471801
//
;(function() {
// Only run in iframes, the same as Metastream webviews
if (window.self === window.top) return
const mainWorldScript = function() {
document.getElementById('metastreaminitscript').remove()
const INIT_TIMEOUT = 5e3
const isFirefox = navigator.userAgent.toLowerCase().includes('firefox')
//=========================================================================
// document.createElement proxy
//=========================================================================
window.__metastreamMediaElements = new Set()
// Proxy document.createElement to trap media elements created in-memory
const origCreateElement = document.createElement
const proxyCreateElement = function() {
const element = origCreateElement.apply(document, arguments)
if (window.__metastreamMediaElements && element instanceof HTMLMediaElement) {
window.__metastreamMediaElements.add(element)
}
return element
}
proxyCreateElement.toString = origCreateElement.toString.bind(origCreateElement)
document.createElement = proxyCreateElement
setTimeout(() => {
if (window.__metastreamMediaElements) {
window.__metastreamMediaElements.clear()
window.__metastreamMediaElements = undefined
}
}, INIT_TIMEOUT)
//=========================================================================
// navigator.mediaSession proxy (Firefox)
//=========================================================================
if (isFirefox) {
// stub out MediaSession API until Firefox supports this natively
if (!navigator.mediaSession) {
const noop = () => {}
const mediaSessionStub = {
__installedByMetastreamRemote__: true,
setActionHandler: noop
}
Object.defineProperty(window.navigator, 'mediaSession', {
value: mediaSessionStub,
enumerable: false,
writable: true
})
function MediaMetadata(metadata) {
Object.assign(this, metadata)
}
window.MediaMetadata = MediaMetadata
}
const { mediaSession } = navigator
// Capture action handlers for player.js proxy
mediaSession._handlers = {}
const _setActionHandler = mediaSession.setActionHandler
mediaSession.setActionHandler = function(name, handler) {
mediaSession._handlers[name] = handler
_setActionHandler.apply(mediaSession, arguments)
}
}
//=========================================================================
// document.domain fix (Firefox)
//=========================================================================
if (isFirefox) {
const domains = ['twitch.tv', 'crunchyroll.com']
// Fix for setting document.domain in sandboxed iframe
try {
const { domain } = document
if (domain && domains.some(d => domain.includes(d))) {
Object.defineProperty(document, 'domain', {
value: domain,
writable: true
})
}
} catch (e) {}
}
//=========================================================================
// Inline script embed prevention fix
//=========================================================================
const observeScripts = () => {
const scriptSnippets = [
{ code: 'window.top !== window.self', replacement: 'false' },
{ code: 'self == top', replacement: 'true' },
{ code: 'top.location != window.location', replacement: 'false' }
]
const getAddedScripts = mutationList =>
mutationList.reduce((scripts, mutation) => {
if (mutation.type !== 'childList') return scripts
const inlineScripts = Array.from(mutation.addedNodes).filter(
node => node instanceof HTMLScriptElement && node.innerHTML.length > 0
)
return inlineScripts.length > 0 ? [...scripts, ...inlineScripts] : scripts
}, [])
// Modifies inline scripts to allow embedding content in iframe
const inlineScriptModifier = mutationsList => {
const scripts = getAddedScripts(mutationsList)
for (let script of scripts) {
for (let snippet of scriptSnippets) {
if (script.innerHTML.includes(snippet.code)) {
script.innerHTML = script.innerHTML.split(snippet.code).join(snippet.replacement)
}
}
}
}
const observer = new MutationObserver(inlineScriptModifier)
observer.observe(document.documentElement, { childList: true, subtree: true })
// Stop watching for changes after we finish loading
window.addEventListener('load', () => observer.disconnect())
}
observeScripts()
}
const script = document.createElement('script')
script.id = 'metastreaminitscript'
script.textContent = `(${mainWorldScript}());`
if (document.documentElement) {
document.documentElement.appendChild(script)
}
})()