Can't send data out of executeScript in chrome-extension - javascript

I am developing one chrome extension which can extract all the meta tags of the current tab. I am using ReactJs as the main development environment and I have placed my chrome related code in its componentWillMount() method.
componentWillMount() {
const code =
"let metas = document.getElementsByTagName('meta');" +
"let newMetas = []" +
"for (let meta of metas) {" +
" newMetas.push({name: meta.name, content: meta.content});" +
"}" +
"newMetas;";
chrome.tabs.executeScript(null, {
code: code
}, function (results) {
console.log(results); // <=== Here I get 'null' value
if (!results) {
return;
}
})}
this is my manifest.json file
{
"manifest_version": 2,
"name": "Northwind",
"description": "Just a simple all with all northwind employees",
"version": "1.0",
"browser_action": {
"default_icon": "./img/ic-logo.png",
"default_popup": "./index.html"
},
"permissions": [
"http://www.amazon.com/",
"tabs"
],
"web_accessible_resources": ["script.js"],
"content_scripts": [{
"matches": ["http://www.amazon.com/*"],
"js": ["app.js"]
}
]
}
app.js is the build file generated by the react.
I have been reading and searching for this but did not get any clues of why it's not working.
Another issue is that when I put console.log('done') in my script, it's not displayed as well so I guess there is some problem with the config as well.
Thanks so much for your help.

When you are using chrome.tabs.executeScript you have to specify host in the permissions field of the manifest.
It is called programmatic injection:
To insert code into a page, your extension must have cross-origin permissions for the page. It also must be able to use the chrome.tabs module. You can get both kinds of permission using the manifest file's permissions field.

Related

Chrome extension service workers stops listening to events after opening popup

I'm developing a chrome extension with MV3.
I've encountered an issue in which when I open the popup when clicking on the extension's icon the service worker background script stops receiving the chrome.tabs.onUpdated events, even after I close the popup. The only way I can make it work again is by reloading the extension.
I will mention that the popup that I'm rendering is a react app, not sure if it has to do with the issue, but when I swap the popup content to a normal HTML with just a button or something it is working as expected
Basically what I'm trying to do in the extension is listen to chrome.tabs.onUpdated event to detect URL changes in the background script, and send a message to a content script in order to save some data to the chrome local storage.
This is the manifest.json -
{
"name": "My Extension",
"description": "Extension POC",
"version": "0.0.0.1",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": ["tabs", "storage", "activeTab"],
"action": {
"default_popup": "build\\index.html",
"default_title": "Open Pane",
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
And this is the background.js -
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (!isPageDoneLoading(changeInfo)) {
return;
}
const url = tab.url;
const ticketId = url.substring(url.lastIndexOf("/") + 1);
if (isTargetURL(url) && !isNaN(ticketId)) {
// Update the ID only if it doesn't equal to the previous one or if null
if (!CURRENT_TICKET_ID || CURRENT_TICKET_ID !== ticketId) {
CURRENT_TICKET_ID = ticketId;
const props = getProperties(ticketId);
chrome.tabs.sendMessage(tabId, { action: {ticketId, props: props} });
}
}
})
Any idea what may be the root cause or how can I resolve the issue?
What React version are you using? In the older React version, part of the create-react-app script creates a file called serviceWorker.js. and a call to it in index.js. When I created a new project with a newer React version, 18.X.X it didn't create this file. I suppose there is some conflict with the service worker of the chrome extension and the one react app created.

How do I use Discord-RPC with Chrome Extension?

I want to make a chrome extension which parses youtube/soundcloud/... pages and gets current song's name. Then it should update user's rich presence status in discord. Like a did it in python there.
I have that one so far. Title already parsed, there's no problem. I have a problem with that code works. Because it doesn't work.
const clientId = '605777168739598338';
const scopes = ['rpc', 'rpc.api'];
const client = new RPC.Client({ transport: 'websocket' });
client.connect();
function updatePresence(title, time, icon) {
title = title.replace(/["]/g, "\\\"");
client.setActivity({
details: title,
startTimestamp: time,
largeImageKey: icon
}, 9999)
}
I also tried raw websocket connection but I'm stupid..
UPD:
The code above is in content.js.
browser.js is a file copied from root of module discord-rpc which i downloaded via npm.
manifest.json
{
"manifest_version": 2,
"name": "Tomori Player",
"version": "0.1.0",
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["browser.js"]
},
"permissions": [
"ws://localhost:6463/*",
"tabs",
"webRequest",
"webRequestBlocking"
],
"content_scripts": [
{
"matches": [
"https://www.youtube.com/watch*",
"https://youtube.com/watch*"
],
"js": ["content.js"]
}
]
}
P.S. I'm so sorry. I'm new in JS.
There's a solution I found:
Chrome Extension parses page and sends sockets to another app
Another app on your PC gets these sockets and then sends RPC to Discord
Timeraa#7947 (PreMiD dev): Discord will disconnect almost immediately if you connect with a browser, trust me i tried. You will need to have an application running in the background
So, you can use PreMiD and push up PreMiD's presences list or make your own app to do it.

Calling API Keys in background and content scripts in WebExtension

I have an API key and secret required for my extension and I've stored them in a file on their own formatted like so.
key.js
var APP_KEY = 'App Key Goes Here';
var APP_SEC = 'App Secret Goes Here';
manifest.json
// manifest.json
{
"manifest_version": 2,
"name": "Trakt for IMDb",
"version": "0.1a",
"background": {
"scripts": [
"js/key.js",
"js/background.js"]
},
"content_scripts": [
{
"js": [
"js/key.js",
"js/main.js"
]
}
]
}
On the popup pages I can just reference this file like <script type="text/javascript" src="../js/key.js"></script> and it calls the 2 variables, but I can't work out how to reference it so my background and content scripts can also access them.
I've tried referencing the key.js file in my manifest.json file as follows
"background": {
"scripts": [
"js/key.js",
"js/background.js"
]
}
But that doesn't work. I'm getting an APP_KEY is not defined
main.js
console.log('Content: ' + APP_KEY);
Is there any way to try do what I'm doing?
This works the way you desire. A single JavaScript file can be used in both background scripts and content scripts to share identical functions or variables.
All the scripts defined in the background key run in the same context. Thus, your variables APP_KEY and APP_SEC, as defined in key.js, are available to your code in background.js.
All the scripts defined in a single js key within a manifest.json file's content_scripts key share a single context. This is what allows you to use things like jQuery with your code. I have not checked to see if there is a separate context created for separate js lists, if the matches key results in both sets being loaded on a particular page, or tab. In addition, I have not checked to see if a single context is shared between the manifest.json file's content_scripts method of loading content scripts and other methods of loading content scripts (e.g. tabs.executeScript‌​()).
The following is a complete extension that has been tested in both Firefox and Google Chrome. In both browsers, the variables defined in key.js are available in both the background and content scripts.
manifest.json:
{
"manifest_version": 2,
"name": "Variables in other files",
"description": "Test availability of variables from anther JavaScript file",
"version": "0.1",
"background": {
"scripts": [
"js/key.js",
"js/background.js"]
},
"content_scripts": [
{
"matches": ["*://*.mozilla.org/*"],
"js": [
"js/key.js",
"js/contentScript.js"
]
}
]
}
js/key.js:
var APP_KEY = 'App Key Goes Here';
var APP_SEC = 'App Secret Goes Here';
js/background.js:
console.log('Background: ' + APP_KEY);
console.log('Background: ' + APP_SEC);
js/contentScript.js:
console.log('Content: ' + APP_KEY);
console.log('Content: ' + APP_SEC);
Console output upon loading extension:
Background: App Key Goes Here
Background: App Secret Goes Here
Console output upon navigating to mozilla.org:
Content: App Key Goes Here
Content: App Secret Goes Here
I am not sure why this did not work for you when you initially tried it. You have stated in a comment that it is working for you now.

Add JS Library to Chrome Extension

I am building a Chrome Extension and I am having trouble adding a JavaScript library to use in my content script.
I am trying to add the Mutation Summary Library. I put the 'mutation_summary.js' file into the extension's directory and I tried to add it by adding 'mutation_summary.js' to the 'manifest.json' file as shown below:
"content_scripts": [
{
"matches": ["http://soundcloud.com/*", "https://soundcloud.com/*"],
"js": ["content_script.js", "mutation_summary.js"]
}
An extension error is thrown when I add it. The errors says "Could not load javascript 'mutation_summary.js' for content script.
Am I adding the javascript library incorrectly?
Thanks
It works perfectly for me. I created an extension with a file called mutation_summary.js which contains console.log('FILE LOADED!'); and it shows up as soon as I load soundcloud.com, maybe you had a typo with the file name?
manifest.json:
{
"name": "Extension",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": ["http://soundcloud.com/*", "https://soundcloud.com/*"],
"js":["mutation_summary.js"]
}
]
}

Chrome Extension that loads Page Source of the active tab

I hope you can help me.
I am trying to create an extension in Chrome which would load a source of the active tab into a variable.
So far I have:
manifest.json
{
"name": "My Extension",
"manifest_version": 2,
"version": "0.1",
"description": "Does some simple stuff",
"browser_action": {
"default_icon": "logo.png"
},
"background": {
"scripts": ["main.js"]}}
main.js
chrome.browserAction.onClicked.addListener(
function(tab) {
var ps1 = document.getElementsByTagName('html')[0].innerHTML;
window.alert(ps1);
});
but that loads the page source of the blank page. What do I need to do to get the source of the active page.
I have done some reading and I think I need to use content script whit some listening functions, I have been searching but all answers seem to me very complicated. Would any of you be so kind to give me some easy example?
Highly appreciate your feedback!
Regards
UPDATE after AdrianCooney answer:
I changed my manifest to contain
"permissions": [
"tabs"
]
Then in main.js I did
chrome.browserAction.onClicked.addListener(function(activeTab) {
chrome.tabs.query({ currentWindow: true, active: true },
function (tabs) {
var ps1=document.getElementsByTagName('html')[0].innerHTML;
window.alert(ps1);
})
});
When I press the Extension button I get something like that
<html></html>
<body><script src="main.js"></script>
</body>
...no matter what tab I have active.
Another try with chrome.tabs.getCurrent
chrome.browserAction.onClicked.addListener(function(activeTab) {
chrome.tabs.getCurrent(
function (tabs) {
var ps1=document.getElementsByTagName('html')[0].innerHTML;
window.alert(ps1);
})
});
The above version of main.js give exact same output as the one before, no matter what page I have active.
Background scripts are isolated from the current page because they're designed to be persistant regardless of the content of the page. You need to use the chrome.tabs API, specifically chrome.tabs.getCurrent. Once you have the current tab, you can inject code into the window. That's where your snippet above comes in.
You will need to add "tab" to your permissions in the manifest file.
As was pointed out, you need to run code in the context of the active tab. One way to do it is using chrome.tabs.executeScript:
chrome.browserAction.onClicked.addListener( function() {
chrome.tabs.executeScript(
{
code: "document.getElementsByTagName('html')[0].innerHTML;"
},
function (ps1) {
window.alert(ps1);
}
);
});
This code under main.js works!!! Thank you guys for your hints they saved me a lot of time!
chrome.browserAction.onClicked.addListener(
function(tab) {
chrome.tabs.executeScript(
null,{
code:"var ps1 = document.getElementsByTagName('html')[0].innerHTML;
window.alert(ps1);"});
}
);
In Chrome 47 you need to add "activeTab" to permissions, otherwise it doesn't work. With "tabs" it doesn't work.
manifest.json:
{
"name": "Rafi extension",
"manifest_version": 2,
"version": "7",
"description": "Open something",
"browser_action": {
"default_icon": "logo.png"
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["main.js"]}
}
For anyone looking to do this with Manifest V3, things are much simpler. Let's say you have a script parse_page.js in the root of your extension, that contains whatever code you want to execute:
var ps1 = document.getElementsByTagName('html')[0].innerHTML;
window.alert(ps1);
From the docs, there are two ways to have it execute:
(1) Inject with static declarations: use this method for scripts that that need to run automatically. Simply add the following to your manifest.json:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["parse_page.js"]
}
],
The script will run whenever you visit a new page. You can adjust the matches above if you only want it to execute on certain URLs.
(2) Inject programmatically: use this method for scripts that need to run in response to events or on specific occasions. Add the following to your manifest.json:
"permissions": ["activeTab", "scripting"],
"background": {
"service_worker": "background.js"
},
"action": { }
Next, in background.js, add the following:
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['parse_page.js']
});
});
In this example, the script will run whenever you click on your extension's icon.

Categories