Skip to content
This repository was archived by the owner on Mar 23, 2025. It is now read-only.

Development Guideline v1 (Deprecated)

Alex Ling edited this page Apr 3, 2022 · 1 revision

First of all, thank you for your interest in contributing! Please read this guideline carefully before you start working on your plugin.

Your plugin folder should have the following structure

.
├── index.js
├── info.json
└── README.md

index.js

Thanks to Duktape and duktape.cr, the plugins can be written in simple JavaScript. The index.js file defines the logic of the plugin. Unfortunately, due to some technical limitations, there's no ES6 syntax support (duktape#2261), and you cannot require other modules in your script (duktape.cr#55).

The JS script should define three functions: listChapters(query), selectChapter(id) and nextPage(). We will go through them in detail here.

listChapters(query)

The function is called by Mango when the user searches something on the plugin download page (/download/plugins), and query is a string containing the user's input.

The function should return a JSON stringified object with two fields: title and chapters. title should be the Manga's title, and chapters should be an array containing some objects, where each object represents a chapter in that manga. Each chapter object should have at least two fields: id and title. id is a unique ID of the chapter containing only alphanumerical characters and underscores, and title is the title of the chapter.

Here's an example:

return JSON.stringify({
  title: 'One Punch Man',
  chapters: [
    {
      id: '866961',
      title: 'Ch. 131 - Heroes Never Lose'
    },
    {
      id: '952595',
      title: 'Ch. 132 - Something Huge'
    },
    // ...
  ]
});

Note that the chapter objects can contain other optional fields like time uploaded and the translation groups, and these fields will be displayed in the table on the download page.

selectChapter(id)

This function is called by Mango when it starts to download a chapter with id. It should return a JSON stringified object with two fields: title and pages. title is the title of the chapter to be downloaded, and pages is the number of images in the chapter.

Here's an example:

return JSON.stringify({
  title: 'Ch. 132 - Something Huge',
  pages: 25
});

nextPage()

This function is called by Mango when it starts to download a page of the selected chapter. It should return a JSON stringified object with two fields: url and filename. url is the URL to the image file, and filename is the filename of the image to be downloaded. Optionally, you can add the third field headers, which is an object representing the headers to use when downloading the image.

Here's an example:

return JSON.stringify({
  url: 'https://domain.tld/path/file.jpg',
  filename: 'file-01.jpg',
  headers: {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0'
  }
});

Helper Functions

Mango provides some helper functions for you to use in your plugin script. They can be accessed from the mango object.

  • mango.get(url, [headers])

This function sends a GET request to url, and optionally you can pass in a second parameter headers. It returns an object with the following fields: body, status_code, and headers.

Example:

mango.get('https://github.com');

// returns the following object
{
  status_code: 200,
  body: "<!DOCTYPE html><html lang=\"en\"> ... </html>",
  headers: {
    "content-type": "text/html; charset=utf-8",
    "server":"GitHub.com",
    // ...
  }
}
  • mango.post(url, body, [headers]) (Mango version > v0.18.0)

This function sends a POST request to url. The request body can be defined with the second parameter, and the third parameter headers is optional. It returns an object with the following fields: body, status_code, and headers.

Example:

mango.post('https://httpbin.org/anything', "Test Body", {"Header1": "Value1", "Header2": "Value2"});

// sends the following data
{ 
  'data': 'Test Body'
  'headers': { 
    'Accept-Encoding': 'gzip, deflate',  
    'Content-Length': '9',  
    'Header1': 'Value1',  
    'Header2': 'Value2',  
    'Host': 'httpbin.org',  
    'User-Agent': 'Crystal'
    // ...
  }
}

// receives the following data
{
  "status_code": 200,
  "body": { 
    'data': 'Test Body'
    'headers': { 
      'Accept-Encoding': 'gzip, deflate',  
      'Content-Length': '9',  
      'Header1': 'Value1',  
      'Header2': 'Value2',  
      'Host': 'httpbin.org',  
      'User-Agent': 'Crystal'
    },  
    'json': null,  
    'method': 'POST'
  },
  "headers": {
    "Content-Type": "application/json",
    "Server": "gunicorn/19.9.0",
    // ...
  }
}
  • mango.css(html, selector)

This function applies the CSS selector and returns an array of matched HTML elements. An empty array is returned when no match is found.

Example:

mango.css('<ul><li>A</li><li>B</li><li>C</li></ul>', 'li');

// returns the following array
["<li>A</li>", "<li>B</li>", "<li>C</li>"]
  • mango.text(html)

This function returns the inner text of html. An empty string is returned when the HTML contains no text.

Example:

mango.text('<a href="https://github.com">Click Me<a>');

// returns the following string
"Click Me"
  • mango.attribute(html, attr)

This function returns the attr attribute of the outmost node. If no matched attribute is found, it returns undefined.

Example:

mango.attribute('<a href="https://github.com">Click Me<a>', 'href');

// returns the following string
"https://github.com"
  • mango.storage(key, [val])

This function can be used to store and retrieve key/value pairs. The data is stored in storage.json in your plugin folder, and Mango will not modify its content.

Usage:

// This stores the login token
mango.storage('login-token', '9fa35e3588c15bf4cc13ee1f4d5043ab');

// This retrieves the login token
var token = mango.storage('login-token');

// If the key does not exist, the function returns `undefined`
mango.storage('heyo'); // undefined
  • mango.raise(msg)

This function raises an exception with error message msg in the upstream Crystal method.

info.json

This JSON file contains the metadata of the plugin. It must contain the following fields: id, title, placeholder, and wait_seconds.

  • id: The ID of the plugin. It should contain only alphanumerical characters and underlines. In principle, it should be identical to the plugin folder name.
  • title: The human-readable title of the plugin.
  • placeholder: The placeholder text to be displayed on the input field on the plugin download page.
  • wait_seconds: The number of seconds to wait before downloading the next page.

Clone this wiki locally