This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

The oil monkey is a Tampermonkey.

The Oilmonkey script runs on top of the Oilmonkey plug-in, which is essentially a reencapsulation of the browser’s capabilities. With that in mind, let’s take a quick look at browser plug-ins.

Browser Extension: A Browser Extension application

To put it bluntly, it is to take the open capabilities of the browser (plug-in API) to implement some small applications.

The browser plug-in consists of four parts: Background Scripts, Content Scripts, global UI elements, and Options Page.

  • Background script: a background script is a separate thread, which is the “eye of God” that floats away from each page. Have the ability to access various plug-in apis, but also lose the ability to directly manipulate the page;
  • content scripts: content script, with the ability to directly manipulate the page. Basically, you run js scripts on the page, using the DOM API.content scriptYou only have direct access to a small number of plug-in apis, but you canbackground scriptTwo-way communication to complete data exchange;
  • Global UI elements: UI interaction at the browser layer, including
    • Display an icon in the Toolbar and define the Popup or other effect that will appear when the icon is clicked
    • Add right click option
    • Added global shortcut keys
    • Modify the new Tab page, history page, bookmarks page
  • Options Page: Plug-in configuration page

The core mechanism of the browser plug-in can be summarized in the following diagram

Most of you are curious about what apis are out there and what you can do with them. Here are a few:

  • contextMenus: Added the right click option
    • Use selected text, for example: underline translation, text collection
    • Quick invocation of plug-in functions, such as: open DevTool, page clipping
  • cookies: Add, delete, change and check cookie (any domain name), directly take the local cookie send request, do not have to do authorization. And because the background script is not a Web page, there are no cross-domain restrictions when sending requests. :
    • Multi-platform information aggregation
    • Multi-platform information distribution
  • devtools.panelsReact Developer Tools, vue.js devTools: Added the Devtool panel, which should be familiar to front-end developers
  • notifications: browser notification, not open the page for notification, can assist some tool applications
  • storage: Saves data globally and synchronizes data with the browser account

Here are just a few examples that I often use, just a drop in the ocean, more API can be read

  • Chrome Extension API Reference
  • Support for extending the Microsoft Edge API
  • Mozilla WebExtensions API

This is the end of the browser plugin, if you are interested in further understanding, recommended: Chrome, Edge, Mozilla three documents.

Tampermonkey

Browser plugins can do all kinds of things, but sometimes developers just want to add a little bit of functionality to a site, and it’s too much trouble to build an environment to package and distribute. From an app market perspective, the market is crowded and cluttered with granular apps.

The Oil Monkey plugin provides a platform for lightweight scripting, instant writing of oil Monkey scripts in an online editor and quick distribution via Github and GreasyFork.

Content Script plays an important role in the Oil Monkey plug-in, running user-written code on the page while providing the GM_xxxx function to encapsulate some of the browser’s capabilities. The internal implementation of the wrapper communicates with the background script and drives the background script to call the plug-in API.

With a brief understanding of the Oilmonkey plug-in, take a look at how to write oilmonkey scripts.

Tampermonkey API

The Oilmonkey script consists of two parts: the header and the core logic

// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
/ / @ version 0.1
// @description try to take over the world!
// @author You
// @match https://www.tampermonkey.net/documentation.php?ext=dhdg
// @icon https://www.google.com/s2/favicons?domain=tampermonkey.net
// @grant none
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...}) ();Copy the code

The header is the meta information of the script, the update method, the page specified to run, the permission declaration, and so on

The configuration of role Use skills
@name The display name of the script Suffixes are added for internationalization. For example, @name: zh-cn specifies the name displayed in Chinese
@namespace The namespace of the script, which can be understood as the identity of the script To avoid conflicts, use the Github repository address
@version Related to updates, current version
@updateURL Check whether the script updates the address Use with @version and automatic update
@downloadURL Where to download the script when an update is detected
@supportURL Where do users go for feedback when they encounter problems
@include Which pages the script runs on Hashtags are not supported. You can declare multiple @include addresses for multiple pages
@match Similar to @ the include
@exclude Which pages the script is forbidden to run on, prior to @include
@require Introduced before the script runsexternalJavaScript files For example, jQuery
@resource The statementexternalResource file, used with GM_getResourceText For example, HTML, icon
@connect Declare the domain accessible to GM_xmlhttpRequest Must be specified to request normally
@grant Declare a list of uses of the GM_xxx function Permission must be specified before normal use
@run-at Specifies when the script will run Document-start: Execute as soon as possible

Document-body: executed when the body is mounted

Document-end: executed when DOMContentLoaded is triggered

Document-idle: DOMContentLoaded Is executed by default

Context-menu: executes when a menu item is clicked
@author The author’s name
@description Brief introduction You can also add suffixes for internationalization
@homepage Home page address If not set and @namespace is the repository address, the default directs to the repository address
@icon Script icon
@icon64 64×64 pixel script icon
@antifeature Whether the script has advertising, mining, data collection and other business activities
@noframes Declare that the script does not run in iframe

The core logic is wrapped in a function that executes immediately, avoiding interference with the global scope. Tampermonkey encapsulates part of the browser’s capabilities as GM_XXX functions to call.

API role Use skills
unsafeWindow Access the Window object of the page
GM_addStyle(css) Create a global style shortcut to insert a style element into the page It can also be created manually using DOM manipulation
GM_addElement(tag_name, attributes)

GM_addElement(parent_node, tag_name, attributes)
Shortcuts to create new elements into the DOM It can also be created manually using DOM manipulation
GM_log(message) Print information on the console Console. log shortcut
GM_setValue(name, value) Persisting data storage
GM_getValue(name, defaultValue) Retrieves data from the storage
GM_deleteValue(name) Deletes data from the storage
GM_listValues() Lists all data items in the storage
GM_addValueChangeListener Monitoring data updates For example, to synchronize data between tabs, you can listen for value to synchronize data
GM_removeValueChangeListener Remove the monitor
GM_getResourceText(name) Gets the declared resource in @resource
GM_getResourceURL(name) Get the declared resource in @Resource (base64 URI form)
GM_registerMenuCommand(name, fn, accessKey) Add options to Tampermonkey’s popup
GM_unregisterMenuCommand(menuCmdId) Remove options
GM_openInTab(url, options) Open a new TAB page
GM_xmlhttpRequest(details) Requests are made using background scripts, with cookies automatically, no cross-domain problems, and the target domain needs to be declared in advance in @Connect
GM_download(details) Download the resource to the local PC
GM_getTab(callback) Gets the current TAB object
GM_saveTab(tab) Re-open a TAB using the TAB object
GM_getTabs(callback) Gets the object of all currently alive tabs to match with other script instances
GM_notification Use the plug-in Notification API to pop up desktop notifications
GM_setClipboard Copy content to clipboard
GM_info Get information about the script’s Oilmonkey plugin

Complete documentation: Tampermonkey Documentation

Practice: Print Hello, World

Do a very simple exercise: create a script called “Hello”, and when you go to the Nuggets and Zhihu page, print “Hello, World” in the Console.

  1. A new script
  2. Changing the script Name
  3. Specify run address@match@include
  4. Direct use ofconsole.logOr declare a permission callGM_log
// ==UserScript==
// @name Hello
// @namespace http://tampermonkey.net/hello
/ / @ version 0.1
// @description try to take over the world!
// @author You Name
// @match https://zhihu.com/*
// @match https://juejin.cn/*
// @grant GM_log
// ==/UserScript==

(function() {
    'use strict';
    GM_log("Hello World"); }) ();Copy the code

Build a comfortable development environment

After experimenting with an online editor, you may also find one

  • Lack of syntax completion and autoprompt
  • Hard to format code

I miss VSCode.

You may also want to consider further, after the online editor has finished editing:

  • How do I sync to a remote repository? How do I distribute code
  • If you use the new syntax, how do you ensure cross-browser compatibility
  • If you write more and more code, how can you manage without modularity
  • Without TS, it is difficult to guarantee long-term maintenance

I’ve stepped through these pits and pulled out a scaffolding tool, create-TamperMonkey-nPM (nPMjs.com), to create a comfortable one-click script development environment for oil Monkey.

Scaffolding integration rollup + Babel + ESLint + typescript supports:

  • Automatically generate UserScript headers
  • Syntax and type system: ESNext, ES Module, TypeScript
  • Style system: CSS Modules, SCSS, SASS, LESS, stylus (need to install corresponding dependencies)
  • Static resources: Import images, convert SVG to Base64, and support SVG Sprite
  • multilingual
  • Extensions: Based on Rollup, plug-ins can be installed on demand for extensions

create-tampermonkeyStart the project

Initialize the project

NPX create-tampermonkey demo-userscript or NPM init tampermonkey demo-userscript or YARN create tampermonkey demo-userscriptCopy the code

After initialization, go to the directory to install dependencies

NPM run dev starts development mode

Open dev.user.js in the browser, and the Tampermonkey script installation page is displayed

Last step: Visit Chrome :// Extension, find the card for the Oil Monkey plugin, and click Details to enter the configuration screen

Check Allow Acess to File URLs

Refresh the page, pop up, and you’re ready.

Open the project with VSCode, and some auxiliary plug-ins will be recommended in the lower right corner. It is recommended to install them.

GM_xxx used in the code is automatically extracted into the UserScript Header and can also be customized in SRC /meta.json.

The default entry to the code is the SRC /main.js file.

Practice: Nuggets check in feature

Based on the above initialization of the project Demo-userscript to do a small function: mining check-in function.

1. Locate the request

The essence of “gold check in” is to call the interface, our implementation idea is to track the request sent when clicking “check in now” button, locate to

2. Debug interfaces

Open Up Postman to do some debugging, and here’s an import trick.

Delete cURL

Go to Postman and use curl to import the entire request: Click the Import button in the left pane, select Raw Text and paste the previous copy.

3. Obtain parameters

[Postman] [Postman] [Postman] [Postman] [Postman] [Postman] [Postman] [Postman]

If you use GM_xmlhttpRequest, it will automatically bring the corresponding cookie, making things easier.

Modify the SRC /main.js code

GM_xmlhttpRequest({
  url: "https://api.juejin.cn/growth_api/v1/check_in".method: "POST".headers: {
    "content-type": "application/json"."user-agent": navigator.userAgent,
  },
  responseType: "json".onload(response) {
    if (response.status === 200) {
      const data = response.response;
      if (data.data === "success") {
        alert("Check in successful");
      } else{ alert(data.err_msg); }}}});Copy the code

Refresh the page to test it out. A refresh at another site can actually send requests, which is the advantage of plug-ins that have no cross-domain restrictions.

Let’s do some throttling optimization. Use GM_setValue and GM_getValue for continuous storage.

const storageKey = "last_sign_timestamp";
// Get the date of the last check-in
const lastSignNumberOfDays = GM_getValue(storageKey, 0);
// Calculate the current day
const currentNumberOfDays = Math.floor(
  new Date().valueOf() / 1000 / 60 / 60 / 24
);

// If already requested today, do not request again
if(currentNumberOfDays ! == lastSignNumberOfDays) { GM_xmlhttpRequest({url: "https://api.juejin.cn/growth_api/v1/check_in".method: "POST".headers: {
      "content-type": "application/json"."user-agent": navigator.userAgent,
    },
    responseType: "json".onload(response) {
      if (response.status === 200) {
        const data = response.response;
        if (data.data === "success") {
          alert("Check in successful");
        } else {
          alert(data.err_msg);
        }
        // Update the last check-in dateGM_setValue(storageKey, currentNumberOfDays); }}}); }Copy the code

It is inevitable to encounter the situation that data needs to be obtained. Generally, there are three kinds of accessible data:

  1. The page contains data, which is retrieved through the DOM
  2. Obtained through the interface request
  3. Stored in localStorage, such as localStorage or cookies

The determination is crude:

  1. Copy the parameter or parameter value to Element for search.
  2. Look at the previous requests to see if there is any trace;
  3. Search in localStorage or cookie.

Distribution of the script

After the script is developed locally, NPM Run Build builds the production version and uploads the code to Github or Gitee.

Distribution can be done directly using the Raw URL of the file on Github/Gitee. If the repository is set in package.json, create-TamperMonkey automatically generates the Raw URL and assigns it to the downloadURL and updateURL.

The problem with this distribution is that you can’t count downloads and maintain both Github and Gitee repositories from a network access perspective. Another distribution option is to upload to the scripting platform Greasyfork.org/, log in and publish new scripts, or use Webhooks to update automatically if the code is hosted on Github or GitLab.

Development skills

Debug the oilmonkey script

The operation of oil monkey script relies on background script and Content Script, and the operating environment needs to be distinguished before debugging. For example, the GM_xmlhttpRequest request is issued by background script. DOM processing and script logic are performed by Content Script.

Once the environment is determined, you can use the appropriate debugging mode for debugging.

debuggingbackground script

Again, visit Chrome :// Extension to find the card for the Oil Monkey plugin

Inspect Views has a background. HTML, click on it to pop up the debug window of background script.

debuggingcontent script

Go to the inspect -> Sources -> Page to find the Tampermonkey directory where the script code is running. Select the target and debug the breakpoint.

To obtainuserIdInformation such as

Sometimes you need to request additional information. There are three ways to do this:

  1. Let’s see if we can find it on the page, get it in the DOM
  2. See if there are any interfaces you can call fetch
  3. See if it’s in local storage

What if the target DOM node is not mounted?

If the node is loaded on the front screen, the crude method is to use setTimeout to delay the node.

However, if you are updating the DOM during an interaction, you have to introduce a listening mechanism, using MutationObserver.

Specific examples can be seen in [Development Record] Digging “ring breaking action” auxiliary script – digging gold (juejin. Cn)

View the plugin source code

After the browser plug-in is installed, the plug-in package is downloaded to a local directory and can be accessed using the following methods.

accesschrome://versionFind the Profile path where the user data is stored.

Visit Chrome :// Extensions/to find the ID of the target plug-in

${Prifile Path}/Extensions/${Extension ID} is the Extension package Path. Note that when accessing the command line, you need to add a \ escape before the space.

conclusion

The browser plug-in uses the capabilities of the browser to extend functions, including cross-domain requests, cookie reading, history management, and right-click item registration.

Browser plug-ins are rich in capabilities and can implement complex functions. But if you just do some operations for the page, only need to rely on the basic ability, you can use the oil monkey script to achieve more convenient development and distribution more quickly.

Develop the Oilmonkey script using the Tampermonkey API and JavaScript.

Create-tampermonkey scaffolding provides a comprehensive oil-monkey script development environment with the latest ES syntax, TypeScript, CSS Modules, and visual studio Code for modular development.

The developed Oilmonkey script can be distributed via the Github/Gitee Raw URL or the Greasy Fork platform.

Browser plug-in is mainly divided into background script and Content Script. When debugging oil monkey script, it is necessary to think clearly about which part of the problem occurs, and then adopt the corresponding debugging mode.

Now that you’ve done two little practices, take the first step and be creative and have fun