chrome.offscreen.createDocument throws undefined error

113 views
Skip to first unread message

Rajveer Sodhi

unread,
May 23, 2024, 8:07:24 AMMay 23
to Chromium Extensions
Hi, I'm trying to create an extension which plays an audio in my offscreen document after being created in the content.js document. However, I get the following error in the Chrome console, saying that the "chrome" object in "chrome.offscreen.createDocument" is not defined. Not sure what to do about that here!
Screenshot 2024-05-22 at 23.29.43.png

Here is my content.js file. This is my first time posting here; please let me know if I should provide any more details or files.

// Try to find the video element immediately
if (!checkForVideoElement()) {
// If not found, use a mutation observer to watch for changes
const observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
if (checkForVideoElement()) {
// Stop observing once the video element is found
observer.disconnect();
break;
}
}
}
});

// Start observing the document body for added nodes
observer.observe(document.body, { childList: true, subtree: true });
}

function checkForVideoElement() {
var video = document.querySelector("video");
if (video) {
console.log(video);

if (video.currentTime <= 60) {
console.log("Video found less than 60s");
// creating offscreen document to play the custom Tudum sound
chrome.offscreen.createDocument({
url: chrome.runtime.getURL("offscreen.html"),
reasons: ["AUDIO_PLAYBACK"],
justification: "Playing Custom Sound"
}, () => {
chrome.runtime.sendMessage("playCustomSound");
});
}

return true;
}
return false;
}

Patrick Kettner

unread,
May 23, 2024, 8:12:04 AMMay 23
to Rajveer Sodhi, Chromium Extensions
Hey Rajveer!
Giving you mentioned content.js, are you attempting to create an offscreen document from a content script? That isn’t allowed. You don’t have access to that API in that context. Offscreen documents are intended for a background script, what is it your attempting to do?

--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/3b153abd-a277-45cd-a449-9341b4f8747fn%40chromium.org.
Message has been deleted

Patrick Kettner

unread,
May 25, 2024, 7:15:30 AMMay 25
to Rajveer Sodhi, Chromium Extensions
Hi Rajveer

That error means that you don’t have a listener setup for your message being sent from your service worker. So you would need to look at the code in your offscreen document to make sure you have a listener setup on document load. 

But, stepping back, I don’t understand why you would do it this way. You are already inside of the DOM in your content script. Why aren’t you just injecting the sound directly in your content script, rather than adding all the indirection of launching an offscreen document?

On Thu, May 23, 2024 at 8:10 PM Rajveer Sodhi <rajveer...@gmail.com> wrote:
Hi Patrick,

Thank you for your response. I was unaware that offscreen elements can only be created by background scripts. I have updated my coed accordingly - it may not be the best workaround right now. Still, now, my content script, after running the checkForVideoElement() function, sends a message to background.js, which in turn initiates the offscreen document. Here is my below code. Could you help me understand why background.js is throwing this error:
Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

updated content.js:
// Try to find the video element immediately
if (!checkForVideoElement()) {
// If not found, use a mutation observer to watch for changes
const observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
if (checkForVideoElement()) {
// Stop observing once the video element is found
observer.disconnect();
break;
}
}
}
});

// Start observing the document body for added nodes
observer.observe(document.body, { childList: true, subtree: true });
}

function checkForVideoElement() {
var video = document.querySelector("video");
if (video) {
console.log(video);

if (video.currentTime <= 60) {
console.log("Video found less than 60s");
chrome.runtime.sendMessage("runOffscreenTask");
// creating offscreen document to play the custom sound
// chrome.offscreen.createDocument({
// url: chrome.runtime.getURL("offscreen.html"),
// reasons: ["AUDIO_PLAYBACK"],
// justification: "Playing Custom Sound"
// }, () => {
// chrome.runtime.sendMessage("playCustomSound");
// });
}

return true;
}
return false;
}


background.js:
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
if (info.status == "complete") {
console.log("Tab updated");
if (tab.url.indexOf("netflix.com/watch/") != -1) {

chrome.tabs.update(tabId, { muted: true });

chrome.scripting.executeScript({
target: { tabId: tabId },
files: ['scripts/content.js']
}, () => {
console.log("Content script injected successfully");
})

// keep the tab muted until the custom Tudum sound has played + remainder of 8 seconds
chrome.storage.local.get("customTudumDuration", function (result) {
let duration = result.customTudumDuration || 0;
console.log("Duration of the custom Tudum sound: " + duration + "ms");
setTimeout(() => {
chrome.tabs.update(tabId, { muted: false });
}, (8000 - duration));
});

}
}
});

chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
if (message === "runOffscreenTask") {
await setupOffscreenDocument('offscreen.html');
chrome.runtime.sendMessage("playCustomSound");
}
});

let creating; // A global promise to avoid concurrency issues
async function setupOffscreenDocument() {
// Check all windows controlled by the service worker to see if one
// of them is the offscreen document with the given path
const offscreenUrl = chrome.runtime.getURL("offscreen.html");
const existingContexts = await chrome.runtime.getContexts({
contextTypes: ['OFFSCREEN_DOCUMENT'],
documentUrls: [offscreenUrl]
});

if (existingContexts.length > 0) {
return;
}

// create offscreen document
if (creating) {
await creating;
} else {
creating = chrome.offscreen.createDocument({
url: chrome.runtime.getURL("offscreen.html"),
reasons: ["AUDIO_PLAYBACK"],
justification: "Playing Custom Sound",
});
await creating;
creating = null;
}
}
Reply all
Reply to author
Forward
0 new messages