I'm trying to write a chrome extension that works with YouTube and need to access some of YouTube's cookie information. I cant seem to get my extension to see any cookies. (Even though I can see them under resources in the "Inspect Element" developer portion of Chrome).
I'm pretty sure I've set up permissions correctly in the manifest 2 file because when I take out the "cookies" permission just to test it I get an error saying "Cannot call method 'getAll'". My current problem is just that no cookies are returned by the callback function.
{
"manifest_version": 2,
"name": "YouTube Viewer",
"description": "This extension is for YouTube videos.",
"version": "1.7",
"icons": {
"128": "ytblack.png"
},
"permissions": [
"cookies",
"https://www.youtube.com/",
"http://www.youtube.com/",
"tabs",
"storage"
],
"background": {
"scripts": ["bootstrap.js"],
"persistent": false
},
"page_action": {
"default_title": "YT View",
"default_icon": "ytblack.png",
"default_popup": "popup.html"
}
}
My manifest calls the bootstrap.js. Inside bootstrap.js there is a call to another file ytview.js but I'm not concerned with that. The code in that is working fine. But inside bootstrap.js my cookies.length is returning as 0 when I look at my "background page" console. The log for "Callback for cookies came in fine." fires correctly. But then it says "cookies.length=0". Like I said, I know the cookies exist because I can see them in the resources.
chrome.tabs.onUpdated.addListener(function(id, info, tab){
// decide if we're ready to inject content script
if (tab.status !== "complete"){
console.log("not yet");
return;
}
if (tab.url.toLowerCase().indexOf("youtube.com/watch") === -1){
console.log("you are not on a YouTube video");
return;
}
chrome.cookies.getAll({domain: "www.youtube.com"}, function(cookies) {
console.log('Callback for cookies came in fine.');
console.log('cookies.length=' + cookies.length);
for(var i=0; i<cookies.length;i++) {
console.log('cookie=' + cookies[i].name);
}
});
chrome.tabs.executeScript(null, {"file": "ytview.js"});
});
Any ideas why no cookies are being returned? Maybe something with "domain" in the .getAll statement? I've tried lots of combinations like www.youtube.com, youtube.com, https://www.youtube.com with no luck.
for future users:
youtube.com use ".youtube.com" as cookie domain to allow the site to share cookies across all youtube subdomains so in your example you should use domain name without 'www' subdomain for example:
chrome.cookies.getAll({domain: "youtube.com"}, function(cookies) {
//...
});
you can clearly see cookies domain using default chrome developer tools
I figured it out. In my manifest I was asking for permission on www.youtube.com but the cookies I was trying to read were on simply youtube.com without the www. Adding the plain youtube.com to the permissions in manifest fixed it.
Related
This is the first time I read about writing Firefox extensions.
What I need is obviously only viable via WebExtensions and both a background and a contentscript. I actually only want to write all open tabs as links in a new tab and then File->Save it. Another alternative Idea was to put it into a JSON Object and save that through a dialog, then I probably could even spare the contentscript but I haven't found anything in the API to download a JSON Object via asking the user to download it via Download Dialog.
Whatever. I think I need to communicate with the content-script then.
I tried to run the following example, but it is not working. When I load the manifest file and open the debugger for extensions, it doesn't log anything and nothing has happened except that the variables myPort and portFromCS seem to be declared without any value.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#connection-based_messaging
// manifest.json
{
"manifest_version": 2,
"name": "Save Open Tabs",
"version": "1.0",
"description": "Save my tabs",
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
// content.js
let myPort=browser.runtime.connect({name:"port-from-cs"});
myPort.postMessage({greeting: "hello from content script"});
myPort.onMessage.addListener((m) => {
console.log("In content script, received message from background script: ");
console.log(m.greeting);
});
// background.js
let portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.postMessage({greeting: "hi there content script!"});
portFromCS.onMessage.addListener((m) => {
portFromCS.postMessage({greeting: "In background script, received message from content script:" + m.greeting});
});
}
browser.runtime.onConnect.addListener(connected);
Why doesn't the example work? Maybe wrong URL matching in the manifest file?
Sorry for my poor English, i hope you can understand the issue.
I'm new to chrome extension development,and for sure in my code there are a lot of
thing to change or optimize;
anyway i've written a simple code that, (seems) works at least from my chrome.
The code clicks a button every X minutes in specific page, then wait and parse the result in page.
I've :
a content script (loaded from manifest.json) which "inject" some button and text Input box in page, so user can sets some "filter params" before click a "start button"; the start button then sendMessage() to background.js to set Alarm Event for the click ;
an eventPage (which is set persistent true in actually ) which handle the request from tabs and set a countdown alarm for each tab; when X min are passed fire a message to the interested tab;
I also have a popup.html e popup.js not important here (i think).
I've to distribuite this extension manually, so i would distribuite a zip that user can load with "developer mode ".
*Now the issue is: why the code was working only on my Chrome ? *
I've tested with others 2-3 laptop with Chrome, the background script is loaded (i can see the background page printint console log)
but in webpage the contents.js seems no way executed .
In my chrome works well: i can see in console some initial output (i print the name of dir extension to check) and
the dynamic created element (button,input box ect.) in page.
And all is working, i can fire the start button and receive results of parsing.
During the development i've never run the extension on other machine. Yesterday i've succssfully tested on 2-3 laptop.. then i made only few change but nothing serious.
Today i can run only in my chrome.
In other pc nothing, neither the simple console.log output first line of script.
I can read in console log :
"Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
but this also in my working istance in my laptop chrome .
The zip file is the same and the extraction is good, in fact i can actually load the extension and i see the background page debug console.log() sentences
In some case, in laptop where it dosen't work, i've received a message relative jQuery and the fact that chrome.runtime.sendMessage() is not defined; and it points to code in webpage, not mine.
I've see that in webpage code there is something like:
var extid = "mcmhdskbnejjjdjsdkksmeadjaibo";
var extVer = "1.5";
var extStatus = 0;
$(document).ready(function () {
///...
chrome.runtime.sendMessage(extid, {message: "version"},
function (reply) {
if (reply) {
if (reply.version) {
if (reply.version == extVer) {
if (reply.gminfo != 'OK') {
extStatus = 1; /// ...
Seems that chrome.runtime is undefined, and the webpage can't call the sendMessage().
EDIT: this undefined occurs only when my extension is loaded
Maybe there is some conflict when i load my extension? But in my chrome browser works...
Can some expert indicate in where direction i've to investigate?
Thanks a lot for any suggestions.
My Manifest.json :
{"manifest_version": 2,
"name": "myAlarm",
"description": "This extension alerts.",
"version": "0.1",
"permissions": [
"alarms",
"system.cpu",
"storage",
"tabs",
"webNavigation",
"https://www.mytargetsite.com/subUrl/"
],
"web_accessible_resources": [
"icon.png",
"vanillaSelectBox.css"],
"content_scripts": [
{
"matches": ["https://www.mytargetsite.com/subUrl/"],
"css": ["vanillaSelectBox.css"],
"js": ["jquery-3.3.1.min.js","vanillaSelectBox.js","taffy-min.js","content.js"],
"run_at": "document_end"
}
],
"background": {
"scripts": ["eventPage.js"],
"persistent": true
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"icons": {
....
}
}
My contents,js (stripped):
chrome.runtime.onMessage.addListener(
function(request, sender) {
// here i parse message "time'up" from background js
});
window.addEventListener('load', function() {
var pt=chrome.runtime.getURL('filterOff.wav');
var p=pt.split("/");
console.log("[myAlarm v0.1] started" );
console.log("[myAlarm v0.1] folder : ("+p[2]+")");
// here i start an active wait for the presence in page of button with ID= btntarget_id
waitForElementToDisplay("#btntarget_id", 500); //when function find button then create and add button and input text to webpage
});
My eventPage.js :
var curr_alarms =[];
chrome.extension.onMessage.addListener(function(request, sender)
{ /// here receive start countdown message from content.js and set alarm ...
}
chrome.alarms.onAlarm.addListener(function(alarm) {
/// here i manage each alarm for each tab
});
chrome.tabs.onRemoved.addListener(function(tabid, removed) {
// ...
});
chrome.tabs.onUpdated.addListener(function
(tabId, changeInfo, tab) {
//
});
edit : in browser where it dosen't work i can read also :
Access to XMLHttpRequest at 'https://mytargetsite.com/suburl/grid.php' (redirected from 'https://mytargetsite.com/suburl/grid.php') from origin 'https://mytargetsite.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
The fact that the declared content script runs or not, should be verified by inspecting in devtools => sources sub-tab => content scripts sub-sub-tab. If it really doesn't run, there can be just two explanations: the URL is different (for example not https) or extensions are blocked by their domain admin via runtime_blocked_hosts which you can see in chrome://policy.
Your development mode extension's id will be different on a different machine unless you pin it by adding a "key" in manifest.json
To use chrome.runtime to send messages to your extension from a webpage code (not from a content script!) your extension's manifest should declare "externally_connectable" and use a different event onMessageExternal, see also sending messages from web pages.
The CORS error may be irrelevant to your code (you can investigate the source of the error by expanding the error's call stack in devtools console).
I made a working Chrome extension that is not packaged and is just a directory on my computer. I found out that I should be able to port this to Firefox rather easily.
I followed the "Porting a Google Chrome extension" guide on MDN and found that my manifest file is perfect.
I then followed the instructions on how to perform "Temporary Installation in Firefox" of the extension.
However, when I click on any file inside the directory, nothing happens. The extension doesn't load. Any advice? I know the extension works in Chrome fine and loads without error.
manifest.json:
{
"manifest_version": 2,
"name": "ER",
"description": "P",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": [ "background.js" ]
},
"content_scripts": [
{
"matches": [ "SiteIwant" ],
"js": [ "ChromeFormFill.js" ],
"run_at": "document_idle"
}
],
"permissions": [
"*://*/*",
"cookies",
"activeTab",
"tabs",
"https://ajax.googleapis.com/"
],
"externally_connectable": {
"matches": ["SiteIwant"]
}
}
ChromeFormFill.js:
// JavaScript source c
console.log("inside content");
console.log(chrome.runtime.id);
document.getElementById("ID").value = chrome.runtime.id.toString();
Background.js
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.data === "info") {
console.log("Recieving Info");
return true;
}
});
chrome.tabs.create(
{
url: 'myUrl'
active: true
}, function (tab) {
chrome.tabs.executeScript(tab.id, { file: 'Run.js', runAt: "document_idle" });
});
Run.js will just alert('hi').
It just won't do anything when I try to load it on Firefox; nothing will happen.
Issues:
In manifest.json:
externally_connectable is not supported:1
Firefox does not support externally_connectable. You can follow bug 1319168 for more information. There is, currently, no expected time when this will be implemented.
You will need to communicate between the code on your site and the WebExtension using a different method. The way to do so is to inject a content script and communicate between the site's code and the content script. The common ways to do this are CustomEvent() or window.postMessage(). My preference is CustomEvent().
Using window.postMessage() is like yelling your message outside and hoping that either nobody else is listening, or that they know that they should ignore the message. Other people's code that is also using window.postMessage() must have been written to ignore your messages. You have to write your code to ignore any potential messages from other code. If either of those were not done, then your code or the other code can malfunction.
Using CustomEvent() is like talking directly to someone in a room. Other people could be listening, but they need to know about the room's existence in order to do so, and specifically choose to be listening to your conversation. Custom events are only received by code that is listening for the event type which you have specified, which could be any valid identifier you choose. This makes it much less likely that interference will happen by mistake. You can also choose to use multiple different event types to mean different things, or just use one event type and have a defined format for your messages that allows discriminating between any possible types of messages you need.
matches value needs to be valid (assumed to be intentionally redacted):
You have two lines (one with a trailing ,, one without; both syntactically correct):
"matches": ["SiteIwant"]
"SiteIwant" needs to be a valid match pattern. I'm assuming that this was changed away from something valid to obfuscate the site that you are working with. I used:
"matches": [ "*://*.mozilla.org/*" ]
In Background.js:
The lines:
url: 'myUrl'
active: true
need to be:
url: 'myUrl',
active: true
[Note the , after 'myUrl'.] In addition, myUrl needs to be a valid URL. I used:
url: 'http://www.mozilla.org/',
A Firefox 48 bug (now long fixed):
Your line:
chrome.tabs.executeScript(tab.id, { file: 'Run.js', runAt: "document_idle" });
In Firefox 48 this line is executed prior to the tab being available. This is a bug. It is fixed in Firefox Developer Edition and Nightly. You will need one of those to test/continue development.
Issues in ChromeFormFill.js:
Another Firefox 48 bug (now long fixed):
chrome.runtime.id is undefined. This is fixed in Developer Edition and Nightly.
Potential content script issue:
I'm going to assume your HTML has an element with an ID = 'ID'. If not, your document.getElementById("ID") will be null. You don't check to see if the returned value is valid.
Running your example code
Once all those errors were resolved, and running under Firefox Nightly, or Developer Edition, it worked fine. However, you didn't have anything that relied on being externally_connectable, which won't function.
agaggi noticed that I had forgotten to include this issue in the original version of my answer.
I am a psychology student and I read papers very often. The university libraries provide the access to the databases but I need to use library search engine and log in every time. Quite annoying. I found a way to avoid jumping around the pages.
Here is the method:
I add "ezp.lib.unimelb.edu.au" to the end of the target database address after I found a paper in Google Scholar, then it will redirect to the library login page.
For example, the paper's address is:
http://www.sciencedirect.com/science/article/pii/S0006899315008550
I modified it as:
http://www.sciencedirect.com.ezp.lib.unimelb.edu.au/science/article/pii/S000689315008550
I want to create a Chrome Extension to finish this job on click (too lazy). I tried for hours but it does not work.
Here is what I have done:
I have three files in a folder:
First file: manifest.json
{
"manifest_version": 2,
"name": "Damn! Take me to the library!",
"description": "This extension automatically adds the 'ezp.lib.unimelb.edu.au' to the browser's address, allowing you to visit the databases bought by the library quickly",
"version": "1.0",
"browser_action": {
"default_icon": "unimelb.png",
"default_title": "Damn! Take me to the library!"
},
"background":{
"scripts":["popup.js"]
},
"permissions": [
"activeTab",
"tabs"
]
}
Second file: popup.js
function getCurrentTabUrlthenChangeIt(callback) {
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
var tab = tabs[0];
var url = tab.url;
callback(url);
var newurl = url.replace('/',"ezp.lib.unimelb.edu.au/");
window.location.replace(newurl);
});
}
Third file: unimelb.png
When I load this folder into Chrome, it does not work.
It's the first time I use JS, anyone has any suggestions?
Thanks!
You can do this even without clicking. You can use the content script for this URL pattern so that your script gets injected to this page. Then you can send a message to the background script using chrome.runtime.sendMessage() and your listener will create a link you want here and then just reload the tab using chrome.tabs.update() with the new URL.
manifest.json
{
"name": "My extension",
...
"content_scripts": [{
"matches": ["http://www.sciencedirect.com/science/article/pii/*"],
"js": ["content-script.js"]
}],
...
}
content-script.js
chrome.runtime.sendMessage({loadURL: true});
background.js
chrome.runtime.onMessage.addListener(function(message, sender, response) {
if (message.loadURL) {
var newurl = sender.tab.url.replace("/", "ezp.lib.unimelb.edu.au/");
chrome.tabs.update(sender.tab.id, {url: newURL})
}
);
This is my first answer to the StackOverflow Community, I hope it helps.
Instead of making an extension, it would be a lot easier to make a bookmarklet which can be used in any browser...
Right click on the bookmark bar
Choose "Add page..."
Under "Name", enter whatever you want "Journal redirect" or whatever
Under "URL", copy and paste the following code (no spaces)
javascript:(function(){location.href=location.href.replace('sciencedirect.com/','sciencedirect.com/ezp.lib.unimelb.edu.au/');})();
Now when you're on the page, click that bookmark and it'll redirect you.
Update: Try this code in the URL for other domains
javascript:(function(){var%20l=location;l.href=l.origin+l.href.replace(l.origin,'ezp.lib.unimelb.edu.au/');})();
manifest.json
{
"manifest_version": 2,
"name": "Damn! Take me to the library!",
"description": "This extension automatically adds the 'ezp.lib.unimelb.edu.au' to the browser's address, allowing you to visit the databases bought by the library quickly",
"version": "1.0",
"browser_action": {
"default_icon": "unimelb.png",
"default_title": "Damn! Take me to the library!"
},
"background":{
"scripts":["background.js"]
},
"permissions": [
"activeTab",
"tabs"
]
}
background.js
//Wait for click
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {
"file": "popup.js"
}, function(){
"popup.js";
console.log("Script Executed ...");
});
})
popup.js
// Change the url to library when on click
var l=location;l.href=l.origin+l.href.replace(l.origin, '.ezp.lib.unimelb.edu.au');
They work well.
It's so cool to finish the first chrome extension. Thank for the help from Mottie.
Anyone looking to edit the url based on some pattern can use the chrome extension Edit Url by Regex
For example for the scenario in this post, while using the extension, you can provide the regex as http.*/science/ and the value as http://www.sciencedirect.com.ezp.lib.unimelb.edu.au/science/
and click submit. The url will get updated as expected.
I know there are many variations of this question already in existence here, but none of them seem to work for me.
Details:
I'm writing an extension that pulls some email data from emails you send in gmail. In order to achieve this I am using this version of Gmailr https://github.com/joscha/gmailr.
In effect, I have three content scripts: Gmailr.js and main.js (which are pretty much identical to those in the link above) allow me to pull out the information I'm looking for. Then content.js I use to send a message to the background page of the extension.
The problem is that from gmailr.js and main.js I cannot use any of the Chrome APIs, and I'm not really sure why, so I can't send messages from these back to the background page.
That is why I made content.js which can communicate with the background page. However, it does not seem to be able to see anything the other content scripts do. For example, main.js inserts a div at the top of the page. When I try to attach an event listener to a button in this div from content.js, I am told that no such element exists.
How can I get the data pulled out by main.js to be seen by content.js? (I also tried to put the data in local storage, then trigger a custom event listener to tell content.js to read local storage, but no luck because they don't seem to be able to hear each other's event being triggered).
Any insight or alternatives are much appreciated.
(I can post code if necessary, but it's fragmented and long)
My manifest file:
{
"manifest_version": 2,
"name": "Email extractor",
"description": "Extracts data from emails",
"version": "1.0",
"background": {
"script": "background.js"
},
"content_scripts": [
{
"matches": [
"*://mail.google.com/*",
"*://*/*"
],
"js": [
"lib/yepnope.js/yepnope.1.5.4-min.js",
"lib/bootstrap.js",
"main.js",
"gmailr.js",
"content.js"
],
"css": [
"main.css"
],
"run_at": "document_end"
}
],
"permissions": [
"tabs",
"storage",
"background",
"*://mail.google.com/*",
"*://*/*"
],
"browser_action": {
"default_icon": "img/icon.png",
"default_popup": "popup.html"
},
"web_accessible_resources" : [
"writeForm.js",
"disp.js",
"/calendar/jsDatePick.min.1.3.js",
"/calendar/jsDatePick_ltr.min.css",
"lib/gmailr.js",
"lib/jquery-bbq/jquery.ba-bbq.min.js",
"content.js",
"main.js",
"background.js"
]
}
This is main.js:
Gmailr.init(function(G) {
sender = G.emailAddress();
G.insertTop($("<div id='gmailr'><span></span> <span id='status'></span>)");
el = document.getElementById("testid");
el.addEventListener('click', mg, false);
var status = function(msg) {
G.$('#gmailr #status').html(msg); };
G.observe(Gmailr.EVENT_COMPOSE, function(details) {
....
status(" user: " + user);
console.log('user:', user);
//now try to send a message to the background page
//this always returns the error that method sendMessage does not exist for undefined
chrome.runtime.sendMessage({greeting: "test from gmailr"}, function(response) {
console.log("did it send?");
});
});
});
gmailr.js is quite long and is also not my own code but it can be seen here: http://pastebin.com/pK4EG9vh
Hi perhaps 3 likely reason to your problem :
The way you send messages to bgp from main.js and gmailr.js are perhaps wrong because you must arrive to communicate from any content script to your bgp. (in your manifest content script key the gmailr.js is missing). Show us your code it would help.
You seems to have a problem with the moment you search from content.js to access to the element created in main.js. Do you try to access your element with the jQuery $("").on() method ? A simple test must be to declare a function in one cs and to use it in another. If it's not working it's a manifest problem. The order you declare .js file in manifest content script key is important also.
try to in the manifest content script array "run_at":"document_end"
Hope it help !