I want to replace a site's CSS file URL through href, i know it's possible to reference external links containing css but what about a local file instead?
document.querySelector("head > link:nth-child(7)").href = "http://example.com/style.css"
One option would be for the local file to be a script, perhaps one that assigns the desired CSS text to a window property, which can then be retrieved inside your userscript. For example:
// ==UserScript==
// #name local
// #match https://example.com
// #require file:///C:/local.js
// ==/UserScript==
document.head.appendChild(document.createElement('style'))
.textContent = window.cssTextFromLocal;
and
// local.js
window.cssTextFromLocal = `
body {
background-color: green;
}
`;
Make sure to permit local file access.
Of course, if you want to do this unconditionally (on every page load, regardless), there's no need for inter-script communication, and you can insert the <style> into the DOM inside local.js.
Like all Chrome extensions, Tampermonkey by default is subject to a number of restrictions designed to prevent developers from acting maliciously. If Tampermonkey had unfettered access to your filesystem, userscript authors could easily abuse the permission to steal or modify your data without your knowledge.
The closest thing you could do would be to host a server on your local machine (e.g. with Node.js). This would allow you to provide Tampermonkey with a URL like localhost/style.css which would be served locally from your computer. This would only work when you had the server running, though.
Alternatively, you could create your own developer-mode Chrome extension which contains the stylesheet within its web_accessible_resources and injects it based on a DeclarativeContent rule. This would be bypassing Tampermonkey entirely, though, so it doesn't exactly answer the question.
Related
I am trying to extract patterns from online PDFs using a client side script (tampermonkey / greasemonkey - Firefox or Chrome). The implementation can be browser specific, would like to try get it working in either 1.
I am able to use JS to extract the content and match on it manually in Firefox (which loads pdf.js automatically). E.g. on a PDF URL:
var matchList = document.body.innerText.match(/my_regex/gi);
I am now trying to port this into Greasemonkey for a user-script:
// ==UserScript==
// #name MyExtractor
// #version 1
// #grant none
// #include *.pdf
// ==/UserScript==
console.log("User script");
console.log(document.body.innerText); // this JS executed manually logs the PDF to text, but
alert("HI");
The script doesn't load - is it possible to get a Gm script to execute on a PDF url in Firefox?
In Chrome, the PDF document seems to be embedded - so even with direct console JS, i can't seem to get access to the content. e.g.
> document.getElementsByTagName("embed")[0]
<embed name="some_id" style="position:absolute; left: 0; top: 0;" width="100%" height="100%" src="about:blank" type="application/pdf" internalid="some_id">
This is about as far as I have been able to get with Chrome - is there a way to get the PDF object based on the above element and extract text from it?
With regards to the JS, i do not necessarily need to have it run directly on the PDF url, I can also get it to identify a page that has a PDF anchor href on it, and then fetch and parse it based on a request if possible - if there is a way to fetch and process with a PDf library some how?
References used so far:
Execute a Greasemonkey script on every page, regardless of page-type (like foo.com/image.jpg)? - do i need to build an extension for this?
Extract text from pdf file using javascript (and followed some of the links) - specifically, i have tried to follow this: How to extract text from PDF in JavaSript - but have not been able to create a reference to the PDF source / add the library to GM and execute as expected - is this a good path to follow and try solve the problems I am running into?
Currently my Office is running a AHK script to pull environment variables. These Env Variables are then used as a specific outputted data when closing tickets as my Office has a ticket closing environment. This works for the time being however I am looking into automating this process and starting off just trying to auto close the tickets when a specific key is pressed. I have been able to perform this task but I have to basically have static variables in the TamperMonkey script for each user. Everyone using this ticket site has the specific environment variables already due to the AHK script and want to try and implement this into the Tampermonkey script without having to change the site completely.
I have locally hosted the site and used Node to do this and I am successful in doing this but it does not work on the Tampermonkey route. I have been using process.env.ENV_VARIABLE on the node side but I am trying to refrain from completely implementing this on the site itself. I have added some basic variable examples in a Autohotkey Script already being used.
GetGreeting() {
global greeting
return greeting
}
GetSalutation() {
global salutation
return salutation
}
GetUserName() {
Envget, e_Ticketname, Ticketuser
return e_Ticketname
}
When a specific Key is pressed it should write the specific message and include said specific Env Variables. Currently I don't think I have it where Tampermonkey can actually understand the Environment Variables as it keeps giving a undefined error. Any Ideas.
So upon further investigation it does not appear to be a way to interact with the OS inside the browser. I will be looking into another way to do what I am looking for. Thank you!
You are able to access and run local files as JavaScript code in Tampermonkey using \\ #require
So if you're able to have a local file with the content in this format:
variables = {
var1: "hello there"
}
Then in the script, add this line and add the path to the file.
// #require file://Path\to\file
Since all the file has is an assignment to a variable, then you can access that in the script
console.log(variables.var1) // logs "hello there"
For this you need to give the extension access to file URLs:
go to chrome://extensions
Tampermonkey > Details
Allow access to file URLs
You'll still need a way to generate the file in that format in the user machine though, either manually, or some code running locally.
A way to generate the file, could be using Node locally, but if you're running that locally, at that point another way to get local data is to serve it using a simple http server (like Node server), then you could make a request from Tampermonkey using fetch or GM_xmlhttpRequest
As a side note, a hack I use to run code locally triggered with Tampermonkey, is to use the localexplorer extension. The extension allows you to open files and folder from the browser using "localexplorer://" urls, so then with javascript you can do window.open(local_url) and it will run or open that file/folder. The file can also be a .bat file, and you can run anything from it (including Node code).
There are some security considerations for using this though if you're worried other websites might be able to open files in your system. but the extension prompts you every time you try to open something with localexplorer
If you're still interested on this, a way I use for it to work without the prompt with less risk is this:
The prompt also lets you click the checkbox of Always open links of this type in the associated app for each domain. So then what you can do, is have a specific domain you choose for this, to always use that domain to open localexplorer links, and use a format of your choosing, like secretdomain.com/?C:\\path\\to\\file, and grant access to always open the links on that domain. Then use Tampermonkey to run some code on that domain so that when it detects that specific url format, to redirect the page to a localexplorer url, like this
location.href.replace(/htt.*:\/\/secretdomain.com\/\?/,'localexplorer:')
Say I have a repository on GitHub with 3 files:
myGreasemonekyScript.js
readme.md
license.md
myGreasemonekyScript.js stores a Greasemonkey script:
// ==UserScript==
// #name facebook
// #namespace nms
// #include http://*.example.com/*
// #include https://*.example.com/*
// #version 1
// #grant none
// ==/UserScript==
// The rest of the script...
Is there a way just to call it from Greasemonkey so that the local Greasemonkey script file will have only an inclusion (an include) of the remote version that sits in GitHub?
Note: The reason I'd like to do that is minimalism, instead having two version localy (the GM script file and a backup in another folder), I would like to center the code editing in one place, without the need to copy changes between each files, each time anew.
I can see four options to do this:
1. Just install the script from github
You will need to tweak the update interval.
All you need to do is to enter Raw view on github and greasemonkey will ask you to install the script. I created an example repository to demonstrate this.
After the script is installed, go into settings and set the auto updating to On:
Further reading: How does user script updating work?
2. Append <script> tag
This is pretty obvious solution but unsuitable for production for security reasons. You can just append script tag to the document, linking your script on github.
3. #require command
This has the flaw that Greasemonkey downloads #require dependencies only once, so you'd need to change something (eg. ?random_number) in URL to force refresh after updating the script.
4. Use my refresher
I once made Node.js script that accepts path to userscript files anywhere on filesystem. It will then search those paths in process.env.appdata+"\\Mozilla\\Firefox\\Profiles\\ap7ptx7o.default\\gm_scripts" (you might need to alter this path) and every time you modify the refference path (the one in your GitHub repo), it will copy it to your userscripts folder.
I'm trying to create a dynamic GM script. Here's what I thought would do it
win = window.open('myScript.user.js');
win.document.writeln('// ==UserScript==');
win.document.writeln('// #name sample script');
win.document.writeln('// #description alerts hi');
win.document.writeln('// #include http://www.google.com/*');
win.document.writeln('// ==/UserScript==');
win.document.writeln('');
win.document.writeln('(function(){alert("hi");})()');
win.document.close();
Well it doesn't. Anyone have any ideas how to go about doing this?
You cannot dynamically create Greasemonkey scripts with Greasemonkey (alone).
A GM script is not part of the HTML page, so writing GM code to a page will never work. The script needs to be installed into GM's script management system.
A GM script cannot write to the file system, nor access sufficient browser chrome to install a script add-on.
You might be able to write a GM script that posts other scripts to a server, and then sends the browser to that server. GM would then prompt the user to install the new script.
You might be able to write a browser add-on that could write GM scripts, but I suspect that this approach will be difficult.
You probably could write a Python (or C, VB, etc.) program that generates GM scripts for installation. With extra work, such a program could probably automatically install the script, too.
Why do you want to dynamically create Greasemonkey scripts, anyway? There may be a simpler method to accomplish the true goal.?.
Update for OP comment/clarification:
Re: "I want to be able to have a user select an element to get blocked and then create a script that sets that element's display to none on all sites from that domain"...
One way to do that:
Store domain and selector pairs using GM_setValue().
The script would, first thing, check to see if it had a value stored for the current page's domain or URL (using GM_getValue() or GM_listValues()).
If a match was found, hide the element(s) as specified in the selector.
Note that, depending on the element, the excellent Adblock Plus extension may be able to block the element much more elegantly (saves bandwidth/DL-time too).
function blah(_x)
{
console.info(_x.toSource().match(/\/\/\s*#version\s+(.*)\s*\n/i));
}
function foobar()
{
// ==UserScript==
// #version 1.2.3.4
// ==/UserScript==
blah(arguments.callee);
}
foobar();
Is there any way to do this using JavaScript? I want to detect the version number / other attributes in a Greasemonkey script but as I understand it, .toSource() and .toString() strip out comments1.
I don't want to wrap the header block in <><![CDATA[ ]><> if I can avoid it, and I want to avoid having to duplicate the header block outside of the comments if possible.
Is this possible? Are there alternatives to toSource() / .toString() that would make this possible?
[1] - http://isc.sans.edu/diary.html?storyid=3231
There is currently no really good way for a Greasemonkey script to know its own metadata (or comments either). That is why every "autoupdate" script (like this one) requires you to set extra variables so that the script will know its current version.
As aularon said, the only way to get the comments from a JS function is to parse the source HTML of the <script> tag or of the file.
However, there is a trick that might work for you. You can read in your own GM script as a resource and then parse that source.
For example:
Suppose your script was named MyTotallyKickassScript.user.js.
Now add a resource directive to your script's metadata block like so:
// #resource MeMyself MyTotallyKickassScript.user.js
Notice that there is no path information to the file, GM will use a relative path to copy the resource, one time, when the script is first installed.
Then you can access the script's code using GM_getResourceText(), like so:
var ThisFileSource = GM_getResourceText ("MeMyself");
//Optional for Firebug users: console.log (ThisFileSource);
You can parse ThisFileSource to get the comments you want.
A script that parses Greasemonkey metadata from a source file is here. You should be able to adapt it with little effort.
Javascript engine will ignore comments, the only way to do that is to string process <script>'s innerHTML, or string process an AJAX request that fetches the .js file, if it was an external file.