Giter Site home page Giter Site logo

luciopaiva / witchcraft Goto Github PK

View Code? Open in Web Editor NEW
251.0 6.0 18.0 4.09 MB

Inject Javascript and CSS right from your file system. Think GreaseMonkey for more advanced users.

Home Page: https://luciopaiva.com/witchcraft

License: MIT License

JavaScript 93.46% HTML 2.57% CSS 3.98%
dotjs greasemonkey

witchcraft's Introduction

Witchcraft

Think Greasemonkey for developers.

Witchcraft is a Google Chrome extension for loading custom Javascript and CSS directly from a folder in your file system, injecting them into pages that match their files names.

It works by matching every page domain against script file names available in the scripts folder. For instance, if one navigates to www.google.com, Witchcraft will try to load and run google.com.js and google.com.css.

For more information on how to install and use it, head to Witchcraft's home page.

Development

Node.js is required, but just to run tests. I also use nvm to manage Node.js versions, but that's not required (just make sure your Node.js version is similar to the one .nvmrc currently points to). To install test dependencies:

cd <project-folder>
nvm install
npm install

Then you're ready to run tests:

npm test

Credits

Witchcraft is my rendition of defunkt's original extension, dotjs. Although I never got to actually use dotjs (it only worked for MacOS and the installation process was not easy), I really wanted something like that. Thanks, defunkt, for having such a cool idea.

Thanks arimus for the idea of using Web Server for Chrome.

The little witch and the witch hat icons were provided by Freepik.

witchcraft's People

Contributors

dependabot[bot] avatar ehershey avatar luciopaiva avatar shihshen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

witchcraft's Issues

Files are still being cached

Hi Luciopaiva,

The PR(#36) to fix file caching issue was merged at March 1, 2021, and the latest version was released before that day. It has been more than 2 years after the fix. Can you release new version soon?

Support for glob matching

Hi Lucio,

Thanks for the great tool, be sure I've already told all my coworkers about it, since it is an idea I wanted to work on for a long time (same issues with dotjs, and the monkey userscripts are just way less user friendly IMHO).

Anyway, I have a feature request, which I'll illustrate with GitHub paths. Say for instance I'd like to have a script for all my project settings github.com/a/b/settings. I must copy for that every project, or create a github.com.js that will look at the url. However, we could solve that one quite fast with glob matching:

github.com/BuonOmo/*/settings.js
github.com/B*/*/settings.js

The glob would act like a bash glob, with only the star pattern since ? may be confusing with urls.

I'd be glad to implement it at some point, just opening the issue for discussion beforehand πŸ™‚

Best regards,
Ulysse

Respond quickly to sites that don't match any script

Considering that for most sites the user won't have any matching script, it would be interesting to be able to quickly return from the extension instead of hitting the file system looking for scripts that don't exist. For instance, say the user loads gist.github.com on their browser. Witchcraft would then be triggered and the follow would happen:

  1. foreground script sends request to background script
  2. background script propagates the request to the local server
  3. local server parses the hostname and collects list of files to look for
  4. ask the file system for ~/.witchcraft/com.css
  5. ask the file system for ~/.witchcraft/github.com.css
  6. ask the file system for ~/.witchcraft/gist.github.com.css
  7. ask the file system for ~/.witchcraft/com.js
  8. ask the file system for ~/.witchcraft/github.com.js
  9. ask the file system for ~/.witchcraft/gist.github.com.js
  10. return response to the background script
  11. call back foreground script with the response

We'd then hit the file system 6 times for a single page load. This happens to each and every page loaded by the browser and it gets worse if you consider that several pages also load iframes as well.

So that's why it would be good to have an in-memory set of all script names that exist under ~/.witchcraft, even if we don't keep the scripts themselves in memory, since it would immensely help pages that don't have any script to be loaded. We could just look for candidate scripts in the set and, if none is found, just return immediately.

Documentation - Easy install path for small footprint / less dev inclined users

Hey,

I found this project through the much beloved, but now defunct dotjs project. I was looking for something for local dev, but also was trying to see if I could easily get this installed on another team member's machine with less dev know-how required to run some custom JS on a specific domain. The Chrome extension is a snap, but node toolchain...not so much. So, instead I:

This only handles the simple case of serving up say a ~/witchcraft/js/localhost file, but this was sufficient for my needs in this case. May be worth mentioning this in the docs as a simple / easy path for anyone that either needs a smaller footprint install or wants to get some of the core functionality without the other moving parts.

Thanks for the software!

screen shot 2018-04-16 at 4 38 10 pm

Inject only once with multiple frames

Hi,
I'm trying to enhance an old web application that I use at work.
This website has a lot of nested frames and iframes, some scripts that force reloads, so for every useful injection of JS/CSS, Witchcraft does 23 (!) unuseful injections!
Is there a way to do injection only once per page?
I'm trying to do it detecting in which frame the script is injected, but the overhead (and wasted RAM) is still huge.

Thank you!

Dario

Cannot assign variables to the window or document scope?

Hi,

Nice work. A question, though:

<!-- https://mydomain.com -->
<html>
  <body>
    <video src="somevideo.mp4">
    <script>
      window.onload = () => 
        document.querySelector('video').play(); // PLAY: I'm not seeing this event...
    </script>
  </body>
</html>
// mydomain.com.js
var video = document.querySelector('video');
video.play = function () {
    console.log('video play called from root window'); // PLAY: ... here
    return this.apply(video);
  }.bind(video);

Why am I not seeing the PLAY event, while I've supposedly overridden the function of the video object?

This works fine in the debugging console of (in this case) Chrome, but not with the plugin.

Any help would be appreciated.

I'm guessing it's related to the fact that I do not seem to be allowed to assign any variables to the javascript in window. When I try to assign something like this:

// mydomain.com.js
window.somedata = {foo: 'bar'};

Opening the console on that window and typing this:

console.log('window.somedata.foo);

Results in:

undefined

Issue with multiple js includes since v. 2.6

My scripts started failing since v. 2.6 of the extension so I did some digging and it seems to be linked to multiple includes in a single file.

in the console, the error is:

ο»Ώblank.html:1 Error in event handler: SyntaxError: Unexpected identifier
at Function ()
at chrome-extension://hokcepcfcicnhalinladgknhaljndhpc/content-script.js:8:9

in the [insert domain here].js file:
`// @include test1.js
var someText = getSomething();

// @include test2.js

alert(hugify(someText));`

test1.js
function getSomething(){ return 'Here goes something'; }

test2.js
function hugify(text){ return text.toUpperCase(); }

I found I could sometimes work around it by nesting include statements e.g. including test2.js inside test1.js and including test1.js only in domainname.js

I did not test this in css, however.

Issue in gmail causes Witchcraft js injection to fail

Witchcraft's CSS code-injection into gmail works just great - and so far I've been able to 're-do' gmail's Inbox so it works very well for a visually-impaired family member. (The attached "Witchcraft_css_injection.png" screenshot shows the 're-done' Inbox at Chrome's default 100% zoom level.)

Witchcraft_css_injection

However, when I tried to inject some js code into the same page, I got the following error message: "The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle."

I then tried the js-injection in Opera, and (somewhere in the process) got a more helpful error message, which directed me to the page at; https://www.chromestatus.com/feature/5527160148197376

I have no idea what the info on the chromestatus page means! But I experimented around in Chrome a bit more - and found that the Witchcraft js code seems to be running twice - with quite different results. For one trial, I used the following code block in the Witchcraft js:

// @include jquery-3.4.0.min.js

$(document).ready(function(){
    console.log("HELLO");
    var pickle = $("body");
    console.log("pickle is: ", pickle);
});

The following "Chrome_error___Witchcraft_js_injection_failure.png" screenshot shows the resulting Console output.

Chrome_error___Witchcraft_js_injection_failure

Note that the expand/collapse arrows are in the expanded mode for both the first & second iterations... BUT, in the second instance, the 'pickle' var has no content! (The additional 'expand' arrows in the first instance work as expected - e.g. clicking on the body.aAU arrow will expand the BODY element in the normal way.)

I realize this is not really a Witchcraft issue - but I'm wondering if you could suggest some workaround that would let me inject Witchcraft js code into gmail.

Either way, I figured you'd probably want to know there was an issue affecting the functionality of this beautiful program. :)

Thanks for your time.

Jeff.

Google analytics is causing couples of issues

Google analytics is causing following issue.

  1. Popup may not work correctly. Sometimes, the server address just shows "host" instead the url and port.
  2. The js and css related to top frame may not be reloaded so the modification of js and css may not be picked up.

I have verified these 2 issues can be fixed by removing google analytics. Can you also let me know why google analytics is needed? As I can see it is sending the URLs users have visited which is part of user behavior. I don't see the necessary to collect user data, and users are not informed when they install this extension.

Thank you,
Shih

Diff code for diff directories of the URL

Thanks for the ext. Working great so far.
I'm wondering how I can apply a different code for a subdirectory in a URL?

For example, I would like to apply some css to mydomain.com, but different code to mydomain.com/subpage. Ideally the css for the subdirectory would not just be added to the high-level domain css, but be the only one loaded, although a solution that only added it would be usable for what I'm trying to do.

First instinct was to use mydomain.com%5Csubpage.css (using the hex character because ofc you can't add a backslash to a filename), but that didn't seem to work.

Thanks!
Hannah

Script count is not working properly

If the page has more than one frame, frames will conflict and the count for the last frame processed is the one that is going to prevail for that tab.

Clever way to fix it: instead of having the foreground script ask for scripts, the background script will listen for tab switching activities. When one happens, it will check if the tab has already loaded Witchcraft scripts. If it has, do nothing; if it hasn't load them now for each and every frame in the tab. That way we can easily count how many scripts were loaded through all frames at once (question: how do we find all the existing frames? And how do we inject scripts in the frames without them asking?).

The other easier way would be to make a note of the frame id as requests arrive (https://developer.chrome.com/extensions/runtime#type-MessageSender) and add them to a set by tab id.

Unclear folder location

After 5 minutes of reading docs, I still don't know which folder the files must be put in.

Quick question: Is it possible to match chrome extensions (i.e. options pages or the LastPass vault)?

First of all, I want to thank you for an amazing library that has totally revolutionized how I use the web! πŸ˜„

My main use case for witchcraft is making buttons and links accessible so that I can access them using vimium. If it is not possible, it is okay, but I would really like to be able to match the settings pages on some of my extensions so I don't have to use my mouse on those pages.

I'm thinking for example of files located at: chrome-extension://<hostname>/index.html

Thank you, regardless of if it is possible! And once again thanks for the awesome library! πŸ˜„

Question: Disable / unload scripts from running -- str.replace HTML before page is loaded ?

I have 2 questions so here goes:

Question 1:

I am wondering what the best practise would be if I were to remove a certain script from running on the page. Take this markup as an example:

Example markup for example domain: theurl.com

<html><head>
  <script src="someurl.com" id="s1">
</head><body>
  <script id="s2">console.log('inline javascript');</script>
</body></html>`

How would I go about writing the theurl.com.js file for removing / disabling the scripts correctly? I did try something like:

theurl.com.js

// attempt 1, directly
document.getElementById('s1').remove();
document.getElementById('s2').remove();

// attempt 2 , after window load
window.addEventListener("load", () => {
    document.getElementById('s1').remove();
    document.getElementById('s2').remove();
});

However it seems that this method isn't working very good as the page freezes up after removing scripts, so I am hoping there is another way of doing this. Any tips would be great!

Question 2:

The other alternative would be if Witchcraft was able to work on the markup before it's delivered to the browser - intercept it in the middle and do some str.replace on the markup. That would be awesome if it were possible, I have done this with http-proxy-middleware in node in a project.

Is it possible for Witchcraft to let me manipulate the HTML before it's loaded by the browser ? If that makes sence. This way I could use regex and string replaces on the markup before the page was loaded - instead of doing itwith javascript.

Cannot remove once added script even after deleting file

I am running witchcraft v2.6.1, and there is a cache problem. Right now I have deleted the js files but they are still added to the page. If I enter the page in normal chrome, the plugin window states server running however no files are included - but they are.

If I open ingognito window, plugin window says files are added and they are. Problem is I have deleted them, and if I click the link from the plugin window I correctoly get a page with 404 as it doesnt exist a file.

So why can this still be included ? There must be some sort of cache somewhere thats been enabled ? I didnt touch chrome in any way, so not sure where to look. I restarted chrome several times but same result. I double checked my file server but it serves the files correctly - only that your plugin magically inserts code from files that doesnt exist anymore.

In-memory cache of scripts

Cache to avoid going to the disk all the time, which can significantly slow down page loading.

This is a more involved enhancement, since the extension would have to know when to invalidate cached scripts. The server could make use of Node's file watch API to know when to refresh them.

Quick item... code example on your homepage

Hey, the code example on your home page appears to have a typo in the JS. Isn't that supposed to be:
window.addEventListener("load", () => { });

This is what I copied from the witchcraft homepage that didn't work:

window.addEventListener("load" => () {
document.querySelectorAll("img")
.forEach(img => img.style.transform = "scaleX(-1)");
});

Thanks for the extension! Looks like it's going to work for highlighting critical incoming emails for me.

@include scripts from the web as well

@include directives are currently restricted to loading local resources only. It would be nice to be able to include scripts from the web as well.

check if scripts exist (v3 branch)

Consider adding a check if scripts exist already on v3 branch, it was adding 4 copies of it on the page.

Changed this in util/embed-script.js:

export function injector(document) {
  if (document.documentElement.querySelector("#witchcraft-script")) return;

  const fnStr = function fn() {
    /*INJECTION_POINT*/
  }.toString();
  const script = document.createElement("script");
  script.id = "witchcraft-script";
  script.text = `(${fnStr})()`;
  // when injecting at document_start, experimentation shows that <head> doesn't exist and <body> may not exist either
  // this is why here we are injecting the script tag directly into <html>, which seems guaranteed to exist
  document.documentElement.appendChild(script);
}

Chrome Web Server Alternatives

I thought I'd raise this as the documentation specifies to use Chrome Web Server.

Since Chrome Web Server has now been shutdown, there are some other alternatives people can use.

My personal preference: Docker
docker run -it -d -p 5743:80 --restart unless-stopped --name witchcraft -v ~/witchcraft-scripts:/usr/share/nginx/html nginx

Then as long as docker is running it'll always work.

Alternatively npm's http-server
cd witchcraft-scripts && http-server -p 5743

Chrome doesnt remember the host url

I have a server on my network where I host the files instead of hosting on the local machine.
The host can be reached and sometimes all works just fine but most of the time the field where I set the url gets reset to host.

image

Sometimes it works, but resets after a few page reloads:
image

How to get a reference to the page level global scope?

I would like to get a reference to the true global scope.

window.load , etc, etc all provide a reference to window that is limited to content scripts.

I see that in the content script that you are using Function to immediately run the script.

What if there was an option to load the content into a script tag. Similar to what you are doing with css (and style tags).

in this way the script should load as if it was a local script and thus have global scope, etc.

maybe there could be a new declaration of

//@mode=X

X===1 means to behave as proposed below
@mode missing or undefined, etc means to behave as you already have it (using Function(scriptContents)())

chrome.runtime.onMessage.addListener(({scriptType, scriptContents}) => {
    if (scriptType === "js") {
        const scriptEl = document.createElement('script');
         scriptEl.type = 'text/javscript';
        scriptEl.appendChild(document.createTextNode(scriptContents));
        scriptEl.setAttribute("data-witchcraft", "");  // to make it easy finding the element if we want to
        document.body.appendChild(scriptEl);
    } else if (scriptType === "css") {
        const style = document.createElement('style');
        style.type = 'text/css';
        style.appendChild(document.createTextNode(scriptContents));
        style.setAttribute("data-witchcraft", "");  // to make it easy finding the element if we want to
        document.head.appendChild(style);
    }
});

Allow for loading of images through the server

Allow the server to respond to image requests. Scripts would inject img tags like this:

<img src="http://localhost:3131/img/some-image.jgp" />

And the server would look for the image in the ~/.witchcraft folder.

File path resolution?

Just a simple user here. I'm trying to get a script to load for "http://trisphere.net/inventory.php". My script folder is "trisphere" and the scripts are "inventory.user.js" and the same script renamed as "inventory.js". Neither of them will load. Help?

The js and css modification is not being picked up by the extension without reloading the page

I noticed the modification is not being picked up by the extension without reloading the page. In the official page, the feature is described as below.
Script changes are seamless
Whenever you edit or create new scripts, there's no need to reload anything other than the page where the scripts are supposed to run. This is what makes Witchcraft special and different from other popular scripting tools, like Greasemonkey or Tampermonkey;

I also don't see how can this be done without polling or websocket in the source code. Have I misunderstood this feature?

Possibility to enable/disable scripts

We at our company would like to manage all our scripts together in one repository. How could we get some individual configuration per user? Now a fork of the repo is the only possibility.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.