drukscode-v2/docs/extensions/userscript.md
OpenCode AI e9899d2e6d
Some checks failed
Android CI Build / check (push) Has been cancelled
Android CI Build / package-apks (push) Has been cancelled
Docs Deploy / build (push) Has been cancelled
Module Market Check / Validate modules/ (push) Has been cancelled
Module Market Publish / Generate submissions.json (push) Has been cancelled
Docs Deploy / deploy (push) Has been cancelled
Initial DruksCode V2: fresh fork of web-to-app (f3b488e) with DruksCode identity
- Package rename com.webtoapp -> br.com.drukstech.codeapp
- Product rename WebToApp/web-to-app -> DruksCode/drukscode
- Design system Wta* -> Dkc*
- applicationId br.com.drukstech.codeapp (.play for gplay flavor)
- rootProject.name DruksCode
- Fresh git history (upstream kept as remote for sync)
2026-09-12 02:42:02 +02:00

3.8 KiB

Userscripts

DruksCode runs Tampermonkey/Greasemonkey-style .user.js scripts with a GM_* bridge. Import a script and it is parsed, stored, and injected like any other extension.

Metadata block

A userscript must contain a // ==UserScript== ... // ==/UserScript== block. Without it, the file is imported as plain JS (isValid = false as a userscript).

// ==UserScript==
// @name         Example Script
// @namespace    https://example.com/
// @version      1.0.0
// @description  Does a thing
// @author       You
// @match        *://example.com/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// @require      https://cdn.example.com/lib.js
// @resource     ICON https://example.com/icon.png
// @noframes
// ==/UserScript==

console.log('Hello from a userscript')

Supported @ tags

@name, @description/@desc, @version, @author, @namespace, @match, @include, @exclude/@exclude-match, @run-at, @grant, @require, @resource (name url), @noframes, @icon/@iconURL/@icon64/@icon64URL, @homepage/@homepageURL/@website.

  • @run-at: document-start → DOCUMENT_START; document-end/document-body → DOCUMENT_END; document-idle (default) → DOCUMENT_IDLE.
  • @match: Chrome glob (<all_urls> → *).
  • @include: if written as /regex/, treated as a regex.
  • @grant none: filtered out.

GM_* API

Both the classic GM_* functions and the Promise-based GM.* (Tampermonkey 4.x) are provided.

API Notes
GM_getValue / GM_setValue / GM_deleteValue / GM_listValues Backed by SharedPreferences, namespaced per script.
GM_xmlhttpRequest Via OkHttp. Supports method, url, headers, data, responseType; callbacks onload/onerror/ontimeout/onprogress; returns {status, statusText, responseText, responseHeaders, finalUrl}.
GM_addStyle Inject a stylesheet.
GM_setClipboard Write to the clipboard.
GM_openInTab Open a URL in a new tab.
GM_log Log output.
GM_notification Simplified — logs only; does not show a system notification.
GM_getResourceText / GM_getResourceURL Read @resource contents.
GM_registerMenuCommand / GM_unregisterMenuCommand Integrated into the floating window menu.
GM_openScriptWindow / GM_updateScriptWindow / GM_closeScriptWindow DruksCode-specific script windows.
GM_info {script:{name,version,description,author,namespace,grants,resources}, scriptHandler:'DruksCode', version:'1.0'}
unsafeWindow Equals window (no sandbox).

The Promise-based GM.* mirrors all of the above (GM.getValue, GM.xmlHttpRequest, …).

::: warning Grants are not enforced Although @grant declarations are parsed and listed in GM_info.script.grants, all GM_* functions are exposed unconditionally — the host does not currently gate APIs by grant. Declare grants anyway for portability with real Tampermonkey/Greasemonkey. :::

@require and @resource

@require scripts and @resource files are downloaded and cached, then injected before your script body.

  • Max single @require size: 5 MB.
  • Max total extension package size: 50 MB.

Injection order: bootstrap (window manager) → GM polyfill → each @require → your script.

Example

// ==UserScript==
// @name         Highlighter
// @match        *://*/*
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

GM_addStyle('mark { background: #fde047; }')
document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('code').forEach(el => {
    const m = document.createElement('mark')
    m.textContent = el.textContent
    el.replaceWith(m)
  })
})