Created
November 4, 2022 01:54
-
-
Save guest271314/a06ebd8bf455effa2f58a774b61ea9a9 to your computer and use it in GitHub Desktop.
Stream same data to all non-chrome tabs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const start = new Date(); | |
let streams = []; | |
let data = [...Array(1000)].map((_, i) => i); | |
let encoder = new TextEncoder(); | |
let resolve; | |
let promise = new Promise((_) => (resolve = _)); | |
let readable = new ReadableStream({ | |
start: async (_) => { | |
// console.log('Original stream'); | |
return promise; | |
}, | |
pull: async (c) => { | |
while (data.length) { | |
c.enqueue(encoder.encode(data.splice(0, 1))); | |
await new Promise((resolve) => setTimeout(resolve, 1000)); | |
} | |
c.close(); | |
}, | |
cancel: (reason) => { | |
console.log(reason); | |
}, | |
}); | |
function parallelStream() { | |
let controller; | |
const stream = new ReadableStream({ | |
start: (c) => { | |
controller = c; | |
return; | |
}, | |
}); | |
streams.push({ | |
controller, | |
stream, | |
}); | |
return stream; | |
} | |
async function readStream(rs) { | |
return rs | |
.pipeTo( | |
new WritableStream({ | |
start(_) { | |
// console.log('Starting tab streaming'); | |
}, | |
write(value) { | |
for (const { controller, stream } of streams) { | |
controller.enqueue(value); | |
} | |
}, | |
close() { | |
console.log('Original stream closed'); | |
try { | |
for (const { controller, stream } of streams) { | |
controller.close(); | |
} | |
} catch (e) { | |
console.error(e); | |
} | |
}, | |
}) | |
) | |
.catch(console.error); | |
} | |
async function createStream({ id, url }) { | |
if (!/^(chrome|chrome-extension):/.test(url)) { | |
return await chrome.scripting.executeScript({ | |
target: { | |
tabId: id, | |
}, | |
world: 'MAIN', | |
args: [`${chrome.runtime.getURL('')}index.html`], | |
func: (src) => { | |
const url = new URL(src); | |
for (const iframe of document.querySelectorAll( | |
`iframe[src*="${url.host}"]` | |
)) { | |
iframe.remove(); | |
} | |
onmessage = async (e) => { | |
if (e.origin === url.origin) { | |
let bool = false; | |
e.data | |
.pipeThrough(new TextDecoderStream()) | |
.pipeTo( | |
new WritableStream({ | |
start() { | |
console.log('start'); | |
}, | |
write(value) { | |
console.log(value); | |
}, | |
close() { | |
console.log(`Stream closed`); | |
}, | |
}) | |
) | |
.catch(console.error); | |
} | |
}; | |
const transferableWindow = document.createElement('iframe'); | |
transferableWindow.style.display = 'none'; | |
transferableWindow.name = location.href; | |
transferableWindow.src = url.href; | |
document.body.appendChild(transferableWindow); | |
}, | |
}); | |
} | |
} | |
async function onClicked(tab) { | |
const tabs = await chrome.tabs.query({}); | |
for (const { id, url } of tabs) { | |
await createStream({ id, url }); | |
} | |
try { | |
readStream(readable); resolve(); | |
chrome.tabs.onUpdated.addListener(onUpdated); | |
} catch (e) { | |
console.error(e); | |
} | |
} | |
async function onUpdated(id, { status }, tab) { | |
if (status === 'complete') { | |
const { url } = tab; | |
try { | |
await createStream({ id, url }); | |
} catch (e) { | |
console.error(e); | |
} | |
} | |
} | |
async function onMessage(e) { | |
if (e.data === 'stream') { | |
try { | |
const rs = parallelStream(); | |
e.source.postMessage(rs, [rs]); | |
} catch (e) { | |
console.error(e); | |
} | |
} else { | |
console.log({time: ~~((new Date() - start) / 60000)}); | |
} | |
} | |
function onInstalled(reason) { | |
console.log(reason); | |
} | |
function onInstall(e) { | |
e.waitUntil(self.skipWaiting()); | |
} | |
function onActivate(e) { | |
e.waitUntil(self.clients.claim()); | |
} | |
chrome.action.onClicked.addListener(onClicked); | |
chrome.runtime.onInstalled.addListener(onInstalled); | |
addEventListener('message', onMessage); | |
addEventListener('install', onInstall); | |
addEventListener('activate', onActivate); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "Parallel stream", | |
"description": "Stream same data to all non-chrome tabs", | |
"version": "1.0", | |
"manifest_version": 3, | |
"host_permissions": ["<all_urls>"], | |
"permissions": ["tabs", "activeTab", "scripting"], | |
"background": { | |
"service_worker": "background.js", | |
"type": "module" | |
}, | |
"web_accessible_resources": [{ | |
"resources": ["*.html", "*.js"], | |
"matches": ["<all_urls>"], | |
"extensions": [] | |
}], | |
"action": {}, | |
"author": "guest271314" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { active } = await navigator.serviceWorker.ready; | |
async function handleMessage(e) { | |
console.log(e.data); | |
if (e.data instanceof ReadableStream) { | |
const readable = e.data; | |
parent.postMessage(readable, name, [readable]); | |
} | |
} | |
navigator.serviceWorker.addEventListener('message', handleMessage); | |
active.postMessage('stream'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment