'How to pass a stream from page to page while the user navigates? Chrome extension Manifest V3
I'm developing a manifest v3 Google Chrome extension that aims to take screenshots and record user browsing.
Problem: When I navigate from one page to another while screen sharing the stream is lost.
Question 1: how to pass the stream between navigation pages?
Question 2: how to store the stream so that when loading the next page the stream is maintained?
Note:
In the service worker I use chrome.desktopCapture.chooseDesktopMedia to bring up the screen sharing window, with this I get the stream id which is then sent to the content script found on the page, where I use navigator.mediaDevices.getUserMedia to get the stream which I then place inside a video element. This video object allows me to take screenshots with canvas.
Viewing some extensions with manifest v2 use the background pages to store the video object and the scripts that create the stream. But now with the service worker in manifest v3, how could I do it?
My code:
Service worker:
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function (msg) {
if (msg.type === 'SS_UI_REQUEST') {
requestScreenSharing(port, msg)
}
if (msg.type === 'SS_UI_TAKESCREENSHOT') {
console.log(msg.top);
StartCountDown(port, msg);
}
});
});
// const sources = ['screen', 'window', 'tab', 'audio'];
async function requestScreenSharing(port, msg) {
const sources = ['screen'];
const tab = port.sender.tab;
chrome.desktopCapture.chooseDesktopMedia(
sources,
port.sender.tab,
streamId => {
if (streamId) {
msg.type = 'SS_DIALOG_SUCCESS';
msg.streamId = streamId;
msg.text = "sharing";
} else {
msg.type = 'SS_DIALOG_CANCEL';
msg.text = "cancel";
}
var tab = getTabId();
tab.then((value) => {
const respuesta = chrome.tabs.connect(value.id, {
name: "respuesta",
});
respuesta.postMessage(msg);
});
}
);
}
let seconds = 3;
let id;
async function StartCountDown(port, msg) {
const css1 = 'body::after{ display: flex; height: 100vh;justify-content: center;align-items: center; background:rgb(76,76,76); opacity: 0.7; content: "Capturando pantalla.. 3"; color:white;font-size: 50px;font-weight: 500; width:100%; position: absolute;top:'+msg.top+'px;left: 0; z-index: 2040;}'
const css2 = 'body::after{ content: "Capturando pantalla.. 2";}'
const css3 = 'body::after{ content: "Capturando pantalla.. 1";}'
myIntervalId = setInterval(function () {
IntervalId = myIntervalId;
if (seconds > 0) {
chrome.action.setBadgeBackgroundColor({
color: [255, 0, 0, 255]
});
chrome.action.setBadgeText({
text: seconds.toString()
});
if (seconds == 3) {
var csstab = getTabId();
csstab.then((value) => {
chrome.scripting.insertCSS({
target: {
tabId: value.id
},
css: css1,
});
});
}
if (seconds == 2) {
var csstab = getTabId();
csstab.then((value) => {
chrome.scripting.insertCSS({
target: {
tabId: value.id
},
css: css2,
});
});
}
if (seconds == 1) {
var csstab = getTabId();
csstab.then((value) => {
chrome.scripting.insertCSS({
target: {
tabId: value.id
},
css: css3,
});
});
}
seconds--;
} else {
chrome.action.setBadgeText({
'text': ''
});
seconds = 3;
clearInterval(IntervalId);
msg.type = 'SS_UI_TAKESCREENSHOT_SUCCESS';
msg.text = "takingScreenShot";
var tab = getTabId();
tab.then((value) => {
chrome.scripting.removeCSS({
target: {
tabId: value.id
},
css: css1,
});
chrome.scripting.removeCSS({
target: {
tabId: value.id
},
css: css2,
});
chrome.scripting.removeCSS({
target: {
tabId: value.id
},
css: css3,
});
const respuesta = chrome.tabs.connect(value.id, {
name: "respuesta",
});
respuesta.postMessage(msg);
});
}
}, 1000);
}
async function getTabId() {
let queryOptions = {
active: true,
currentWindow: true
};
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
content-script
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function(msg){
if (msg.type === 'SS_UI_REQUEST') {
console.log(msg);
if(!window.stream)
{
var messenger = chrome.runtime.connect();
messenger.postMessage(msg);
}else
{
console.log(msg);
var messenger = chrome.runtime.connect();
messenger.postMessage({ type: 'SS_UI_TAKESCREENSHOT', top: window.scrollY.toString() },'*');
}
}
if (msg.type === 'SS_DIALOG_SUCCESS') {
startScreenStreamFrom(msg.streamId);
console.log(msg);
var messenger = chrome.runtime.connect();
messenger.postMessage({ type: 'SS_UI_TAKESCREENSHOT', top: window.scrollY.toString() },'*');
}
if (msg.type === 'SS_UI_CHANGE_CSS') {
console.log(msg);
}
if (msg.type === 'SS_DIALOG_CANCEL') {
console.log(msg);
}
if(msg.type === "SS_UI_TAKESCREENSHOT_SUCCESS")
{
console.log(msg);
setTimeout(function() {
TakeScreenShot();
}, 300);
}
if(msg.type === "SS_UI_RECORDSCREEN")
{
console.log("Grabar pantalla");
RecordScreen();
}
});
});
function startScreenStreamFrom(streamId) {
console.log("compartiendo pantalla");
navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId
}
}
})
.then(stream => {
var video = document.getElementById("ElementNotExist");
if(video)
{
video.remove();
}
window.stream = stream;
window.stream.getVideoTracks()[0].onended = function () {
window.stream = null;
};
var video = document.createElement('video');
video.srcObject = stream;
video.type = 'video/ogg';
video.autoplay = true;
video.setAttribute("id","ElementNotExist");
video.style.display = "none";
document.body.appendChild(video);
});
}
Index.js Extension script.
document.getElementById("btn-capture").addEventListener("click", function () {
var tab = getTabId();
tab.then((value) => {
chrome.storage.local.set({ 'pestaña': value.id });
const port = chrome.tabs.connect(value.id, {
name: "conexion",
});
port.postMessage({ type: 'SS_UI_REQUEST', text: 'start' }, '*');
window.close();
chrome.action.setPopup({popup: "capture.html"});
});
})
async function getTabId() {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
