In Chrome Manifest V2 I was able to easily capture the desktop. Attempting this in Manifest version 3 I have had no luck. I feel I may be missing something here in attempting this in Manifest V3.
I have been using this as a reference. https://developer.chrome.com/docs/extensions/reference/desktopCapture/
My manifest has these permissions granted to it
"permissions": [
"idle",
"tabs",
"storage",
"notifications",
"alarms",
"desktopCapture"
],
This is the sample code I have been testing just to see if I can get the screen selector to come up. I have not included the tabs.tab as this is labeled as optional and I wanted to see if I could have the plugin trigger the screen recording feature on its own.
chrome.desktopCapture.chooseDesktopMedia(["screen"], (streamID, options) => {console.log(id)});
I have been attempting to have this run in my background.js file.
Each time it runs chrome crashes completely with no errors given.
Reviewing the crash dump I can see the following information.
Exception Code: 0xC0000005
Exception Information: The thread tried to read from or write to a virtual address for which it does not have the appropriate access.
I solve it this way for Manifest v3.
It was giving me errors too. When I checked the documentation, chooseDesktopMedia it wanted three parameters.
DesktopCaptureSourceType[]
Tab
Callback Function
I see in your question your have put 1 and 3. I did the same it was giving me errors. So I made sure I get the active tab first before calling chrome.desktopCapture.chooseDesktopMedia in the background script.
So the code looks like this
chrome.tabs.query({ active: true }, (tabs) => {
if (tabs.length) {
const tab = tabs[0];
var pending = chrome.desktopCapture.chooseDesktopMedia(["window"], tab, (streamId) => {
//console.log(streamId, tab);
});
}
return false;
})
And it worked. I hope this helps
Related
I'd like to write an extension for Thunderbird that modifies the message display (e.g. insert/replace text/markup/image).
Unfortunately, the documentation is lacking (due to recent changes?).
https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Thunderbird_extensions
is outdated
https://developer.thunderbird.net/
does not have useful examples (yet)
https://thunderbird-webextensions.readthedocs.io/
no examples either
Some examples can be found at
https://github.com/thundernest/sample-extensions
Building on https://github.com/thundernest/sample-extensions/tree/master/messageDisplay
I've modified background.js
browser.messageDisplay.onMessageDisplayed.addListener((tabId, message) => {
console.log(`Message displayed in tab ${tabId}: ${message.subject}`);
console.log(message.id);
browser.messages.getFull(message.id).then((messagepart) => {
console.log(messagepart);
body = messagepart['parts'][0]['parts'][0]['body'];
console.log(body);
body += "modified!";
console.log(body);
});
browser.windows.getCurrent().then((window)=>{
console.log(window.type);
});
browser.tabs.getCurrent().then((tab)=>{
console.log("tab",tab);
});
});
which gives me the message body (using magic indexes) but expectedly, the change is not reflected in the message display.
The window type returned is normal, not messageDisplay.
The tab is undefined despite adding permissions
"permissions": [
"messagesRead",
"activeTab",
"tabs",
"tabHide"
],
but I assume that's because the script is running as background.
So I'd need a script running on the content / access to the tab and then some hints on how to modify the displayed message content (I do not want to modify the message).
Where would I find the equivalent documentation to
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts
specific to Thunderbird?
Specifying content_scripts in manifest.json causes "Error: Error reloading addon messageDisplay#sample.extensions.thunderbird.net: undefined".
executeScript() from background does not seem to work either, even with tabId specified.
This was not possible to do when you wrote your question, the API for modifying displayed messages was missing.
As of this writing (September 2020), the browser.messageDisplayScripts API landed a few days ago, see bug 1504475 and related patch for examples. It works as follows: You can register your content script (to modify the displayed messages) like this
let myPromise = browser.messageDisplayScripts.register({
css: [{
file: "/style.css",
}],
js: [{
file: "/content_script.js",
}],
});
And you can later unregister with
myPromise.then((script) => { script.unregister(); });
You need to register the script just once for all messages (you do not need a listener that would load it each time a message is displayed).
Note that your manifest.json needs to include the messagesModify permission for this to work.
The new API will be in Thunderbird version 82, so if I understand the release process correctly it should be in stable version 88 (unless it is backported before that). You can try it already (v82 is the current EarlyBird).
Documentation https://thunderbird-webextensions.readthedocs.io/en/68/tabs.html#getcurrent
says:
May be undefined if called from a non-tab context (for example: a background page or popup view).
Since the background.js is not called from a tab context the tab is undefined.
I found several approaches, but they seem outdated or simply won't work for some reasons for me. Maybe tunnelvision:
First things first:
I have the correct permissions in my manifest.json, I think:
"permissions": [
"tabs",
"activeTab"
]
I have 2 simple scripts, background.js and content.js (which are recognized correctly, the error can't be here).
In my background.js I tried several approaches:
chrome.browserAction.onClicked.addListener(buttonClicked);
var sharedUrl;
function buttonClicked(tab) {
chrome.tabs.getCurrent(function(tab) {
// please read further, this was my last resort, I tried other stuff as well
sharedUrl = console.log(window.location.href);
});
let msg = {
txt: "Hello",
url: sharedUrl
}
chrome.tabs.sendMessage(tab.id, msg);
}
I tried it with getCurrent() and then tab.url, but that didn't work (neither with tab[0].url
I tried it also with getSelected() as well as with something like this:
chrome.tabs.query({active: true, currentWindow: true}, function(arrayOfTabs) {
var activeTab = arrayOfTabs[0];
});
and my content.js is simply this here:
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendResponse) {
console.log(message.txt);
console.log(message.url);
}
It displays "Hello", but not the URL I'm looking for.
Edit:
It might of importance, that I want to retrieve the url after a button-click in my extension.
Thanks for the feedback and help.
Ok, based on the documentation you are not able to grab the tab object while you are not in the tab context. The tab context includes only content scripts. So you can't access to tab because you are calling it from your backend page. You can only do it, if your extension has generated the tab.
Gets the tab that this script call is being made from. May be
undefined if called from a non-tab context (for example: a background
page or popup view).
So, the only possible way is to change your extension data flow.
I am trying to execute a script that shows a green border on the specified tab (by ID). The script should execute when the response for the requested URL is an error. The problem is that, when I load the extension from about:debugging, I get the following error (in the browser console in FF 53):
Error: No window matching {“matchesHost”:[“<all_urls>”]}
I searched for hours and hours and looked at several posts for similar problems but none of them have helped me. For example, this post suggests adding "<all_urls>" permission and it did not help in my case. Another post says that it is not possible to execute script in certain type of hosts such as about:[anything] pages and mozilla pages. I do not see my URL belongs to any of them.
Here is my example:
The manifest.json
{
"manifest_version": 2,
"name": "test",
"version": "1.0",
"background": {
"scripts": ["test.js"]
},
"permissions": [
"<all_urls>",
"activeTab",
"tabs",
"storage",
"webRequest"
]
}
The background script is test.js:
console.log("-- inside js file --");
var target = "<all_urls>";
function logError(responseDetails) {
errorTab=responseDetails.tabId;
console.log("response tab: "+errorTab);
var makeItGreen = 'document.body.style.border = "5px solid green"';
var executing = browser.tabs.executeScript(errorTab,{
code: makeItGreen
});
}//end function
browser.webRequest.onErrorOccurred.addListener(
logError,
{urls: [target],
types: ["main_frame"]}
);
The error you are seeing:
Error: No window matching {"matchesHost":["<all_urls>"]}
is generated when you attempt to inject a script using tabs.executeScript() (or CSS with tabs.insertCSS()) in a tab that is currently displaying a URL which you do not have permission to inject into. In this case, you have specified in your manifest.json the host permission "<all_urls>". The fact that "matchesHost":["<all_urls>"] is displayed indicates that Firefox is aware of your "<all_urls>" permission. That you have still gotten the error means that you have attempted to inject into a URL which does not match <all_urls>.
As you have mentioned, Firefox does not permit injecting into about:* pages. In addition, injecting into pages at the domain addons.mozilla.org is not permitted. None of those pages will match <all_urls>. All such URLs will generate the above error if you attempt to inject into tabs showing them.
But, I'm injecting into some normal URL that had an error
All easily obtainable information to the contrary — including the URL provided in the tabs.Tab data obtained from tabs.get() —, the page you are attempting to inject into is, in fact, an about:* page, not the page (that doesn't exist) at the URL where you got the error. While the URL reported in the tabs.tab structure for the tab in which you received the error will show the URL on which the error occurred, the actual URL for the page being displayed is something like:
about:neterror?e=dnsNotFound&u=[URL you were attempting to get to, but encoded as a query string]
I know this because the last webNavigation.onDOMContentLoaded event when I tested attempting to load the URL: http://www.exampleahdsafhd.com/ was:
webNavigation.onDOMContentLoaded - > arg[0] = Object {
url: "about:neterror?e=dnsNotFound&u=http%3A//www.exampleahdsafhd.com/&c=UTF-8&f=regular&d=Firefox%20can%E2%80%99t%20find%20the%20server%20at%20www.exampleahdsafhd.com.",
timeStamp: 1497389662844,
frameId: 0,
parentFrameId: -1,
tabId: 2,
windowId: 3
}
The fact that the error page is an about:* page, means that you will not be able to inject scripts, or CSS, into it. This means that you will need to find some other way to accomplish what you desire and/or adapt what you desire to do to what is possible. One possibility would be to navigate to a page within your extension which describes the error.
I am writing a chrome extension which detects the type of file being opened and based on that injects a script on the page which does many other things. Here is the part of my code for the background.js which is injecting the script:
chrome.webRequest.onHeadersReceived.addListener(function(details){
console.log("Here: " + details.url + " Tab ID: " + details.tabId);
if(toInject(details))
{
console.log("PDF Detected: " + details.url);
if(some-condition)
{
//some code
}
else
{
chrome.tabs.executeScript(details.tabId, { file: "contentscript.js", runAt: "document_start"}, function(result){
if(chrome.runtime.lastError)
{
console.log(chrome.runtime.lastError.message + " Tab ID: " + details.tabId);
}
});
}
return {
responseHeaders: [{
name: 'X-Content-Type-Options',
value: 'nosniff'
},
{
name: 'X-Frame-Options',
/*
Deny rendering of the obtained data.
Cant use {cancel:true} as we still need the frame to be accessible.
*/
value: 'deny'
}]
};
}
}, {
urls: ['*://*/*'],
types: ['main_frame', 'sub_frame']
}, ['blocking', 'responseHeaders']);
Here is the manifest file:
{
"manifest_version": 2,
"name": "ABCD",
"description": "ABCD",
"version": "1.2",
"icons": {
"16" : "images/16.png",
"32" : "images/32.png",
"48" : "images/48.png",
"128" : "images/128.png"
},
"background": {
"scripts": ["chrome.tabs.executeScriptInFrame.js", "background.js"],
"persistent": true
},
"permissions": [
"webRequest",
"<all_urls>",
"webRequestBlocking",
"tabs",
"nativeMessaging"
],
"web_accessible_resources": [ "getFrameId", "aux.html", "chrome-extension:/*", "images/*.png", "images/*.gif", "style.css"]
}
The problem is that when injecting script the last error part runs and it shows the tab was closed and the script is not injected. If I press enter on the omnibox a several times the script is injected and things work fine. Here is a sample run of events:
Sorry for my naive photo editing :P
There are a few more things we can deduce from this image:
The first thing being loaded in the tab with tab id 86 is something related to my google account. I have logged out and also turned off the prerender feature of chrome.
On pressing enter several times the tab was closed error goes but the script which maintains a chrome.runtime connection with the background.js gets disconnected.
And then finally things work fine.
I have been banging my head around this for days. No other question on SO addresses this problem. Nor anywhere else on the internet as well.
EDIT:
One more thing to note: The sample run shown in the image above is one such. There are many different behaviors. Sometimes 3 enters wouldn't make it work. Sometimes just one will. Is there something wrong because of the custom headers i am sending?
UPDATE #1
One must notice the headers I am returning in OnHeadersReceived. It's being done to stop chrome from rendering the document. But on doing that all the data of the file is dumped on the screen and I don't want that to appear. So i think I need document_start so that I can hide the dumped data before my content script does other things like putting a custom UI on the page.
UPDATE #2
Noticed one more thing. If I open a new tab, and then paste a url there and then press enter the following is the output of the background page on the console.
So I guess, the location of the window is updated at a later time by chrome. Am I right? Any workarounds?
"The tab was closed" error message is a bit misleading, because the tab obviously is not closed. In chrome sources the variable with the string is called kRendererDestroyed. So the error is because the corresponding renderer is being destroyed for some reason.
I was getting the error if the the page opened in tab redirected (thus one renderer destroyed, another one created for the same tab, but different url this time), in this case extension will got tab updates with statuses like:
loading url: 'example.com', here tab is already returned to callbacks etc, but will get the error, if tried to inject script
loading url: 'example.com/other_url'
title: 'some title'
complete
I managed to get around by injecting script only after receiving status: 'complete' (but probably injecting on title should also do)
Did not try with pdfs, but chrome probably will replace renderer for those too like with a redirect. So look more into page statuses and redirects/renderer replaces. Hope this helps anyone stumbling upon this question.
A simple setTimeout call to wait for the page to load worked for me.
I developed a google chrome extension that works good with Windows OS. but the problem that does not work with mac, I tried to check the problem, I found that function
chrome.tabs.executeScript
does not work on mac, this is the completely code that worked good with windows not mac.
// The onClicked callback function.
function onClickHandler(info, tab) {
// the problem in injecting code
chrome.tabs.executeScript
( null,{code:"var activeElm = document.activeElement; var inp_text = activeElm.value; console.log(activeElm.value);"});
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
// Set up context menu tree at install time.
chrome.runtime.onInstalled.addListener(function() {
// Intentionally create an invalid item, to show off error checking in the
// create callback.
console.log("About to try creating an invalid item - an error about " +
"duplicate item child1 should show up");
chrome.contextMenus.create({"title": "consoleMe", "id": "child523", "contexts":["selection"]}, function() {
if (chrome.extension.lastError) {
console.log("Got expected error: " + chrome.extension.lastError.message);
}
});
});
Hint:
I use content_scripts injection files in the manifest file, but it seems did not activated on Google chrome on Mac.
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js" : ["jquery.min.js","fix.js","injscript.js"],
"all_frames": false
}
],
OS : Mac 10.8 Mountain lion --
Google Chrome V 32
There should be no difference between Windows and Mac. It's likely that something else is different between your two setups.
It's not clear to me whether the javascript snippet above is a background script or an injected content script. Can you provide the full manifest and indicate which file the snippet belongs to?
If it's a background script, chrome.tabs.executeScript with null tabId will apply to the background page, which is not what you expect. Instead, pass tab.id for the tabId.
If it's a content script, the contextMenus API calls won't work because content scripts are not allowed to use chrome APIs (see https://developer.chrome.com/extensions/content_scripts.html).