1

I'm making a website to post some scripts that I made, I would like to create a button on my page to dynamically install the UserScript with Tampermonkey or Greasemonkey, just like in Greasyfork.

Page example: Script example

3
  • 1
    I believe that, if the file you are downloading ends in .user.js and you have a UserScript extension installed, a installation propmt is triggered. Commented Mar 1, 2021 at 19:20
  • well, if it does trigger, its not triggering for me Commented Mar 2, 2021 at 3:24
  • its not download, you need to open this file url, exemple: window.open("./myDirectory/myFile.user.js") Commented Mar 2, 2021 at 4:44

1 Answer 1

1

You can try to trigger a download using a hidden <a> element with a download attribute set to the filename ending in .user.js. You might need to enable some settings in your browser to detect downloading opening of UserScripts.

Note: You may need to send the text to a server (PHP, Node, etc...), save the file as *.user.js and then create an <iframe> with an href poiting to the filename on the server to trigger a proper file download/install. When you install a script on Greasyfork, it downloads a *.user.js file that is hosted on their server(s). The filename that is downloaded fits the following the pattern:

https://greasyfork.org/scripts/<ID>-script-name/code/Script%20Name.user.js

Downloading scripts from the client or local file system is frowned upon in modern web dev.

const download = (content, mimeType, filename) => {
  const
    a = document.createElement('a'),
    blob = new Blob([content], {type: mimeType}),
    url = URL.createObjectURL(blob);
  a.setAttribute('href', url);
  a.setAttribute('download', filename);
  a.click();
  console.log(`Downloading: ${filename}`);
};

const extractFilenameFromScript = (script) => {
  const [, scriptName] = script.match(/^\/\/\s*@name\s+(.+)$/m);
  return `${scriptName.replace(/[^a-z0-9]+/ig, '-').toLowerCase()}.user.js`;
};

const downloadScript = () => {
  const script = document.querySelector('.user-script').textContent.trim();
  const filename = extractFilenameFromScript(script);
  download(script, 'text/javascript', filename);
};

document.querySelector('.download-btn').addEventListener('click', downloadScript);
.user-script {
  width: 100%;
  height: 8em;
}
<textarea class="user-script">// ==UserScript==
// @name         My Awesome Script
// @namespace    com.stackoverflow.questions
// @version      1.0.0
// @description  An example UserScript to download
// @author       Mr. Polywhirl
// @match        https://stackoverflow.com/questions/66428142
// @grant        none
// ==/UserScript==
(function() {
    'use strict';
    alert('Hello World');
})();
</textarea>
<button class="download-btn">Download</button>

Sign up to request clarification or add additional context in comments.

3 Comments

The script.match(/^\/\/\s*@name\s+(.+)$/m); part is confusing and gives a error. What does that do?
@LuísHNrique it just extracts the name in the actual script.
i got it, the error was caused becouse of the ^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.