Nyxovira Plugin API KapiTomo documentation

Create plugins for Nyxovira

A plugin connects Nyxovira to a reading site, shows the chapter list quickly, and prepares only the chapters selected by the user.

Developer path

3. Keep it for yourself

If only you will use the plugin, no publication, catalog, or website is required.

How a plugin works

The creator prepares plugin.json and browser/download_target.js.

During development, the creator imports the local plugin folder into Nyxovira and tests it on the supported site.

The plugin may remain private. Publication is optional and happens only after testing.

On supported pages, the browser script shows chapters immediately and prepares the selected content after confirmation.

Plugin files

Place the manifest and browser script inside one folder named after the plugin id.

my-plugin/
|-- plugin.json
`-- browser/
    `-- download_target.js
FilePurpose
plugin.jsonDefines the plugin id, version, host, browser entry, icon, and parser.
browser/download_target.jsRuns inside the open page and builds the work download plan.

plugin.json

The manifest describes the site and tells Nyxovira which browser script to run.

{
  "schema_version": 1,
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "tags": ["english", "manga"],
  "match": { "hosts": ["example.com"] },
  "browser": {
    "home_url": "https://example.com/",
    "icon_url": "https://example.com/icon.png",
    "icon_mode": "pinned",
    "short_label": "Source",
    "download_target_script_file": "browser/download_target.js"
  },
  "parser": {
    "adapter": "html_series",
    "base_url": "https://example.com"
  }
}

Site mapping

Map the site's names to the fields Nyxovira expects: title, cover, chapters, text, and page images.

var plugin = {
  siteBaseUrl: "https://example.com",
  siteVariable: "EXAMPLE_WORK_INDEX",
  siteRoutes: {
    detailsHash: "series",
    readerHash: "reader"
  },
  appRoutes: {
    publicSeriesPath: "manga",
    publicChapterPath: "chapter"
  },
  fields: {
    workId: "slug",
    workTitle: "name",
    workSummary: "synopsis",
    workCover: "cover_url",
    workChapters: "episodes",
    chapterParagraphs: "text_blocks",
    chapterPages: "page_urls",
    imageSource: "url"
  }
};

Instant chapter list

When the user taps download, set window.__nyxoviraChapterPlan immediately and return the canonical work URL.

window.__nyxoviraChapterPlan = JSON.stringify({
  title: "Work title",
  summary: "Short summary",
  canonicalUrl: "https://example.com/manga/work/",
  coverUrl: "https://example.com/cover.png",
  chapters: [
    {
      id: "chapter-forest-hunt",
      number: "1",
      title: "The Forest Hunt",
      contentType: "novel",
      paragraphs: ["First paragraph.", "Second paragraph."]
    }
  ]
});

return "https://example.com/manga/work/";

Prepare after selection

For large comics or APIs, keep the first plan lightweight. Load page URLs only after the user confirms selected chapters.

window.__nyxoviraPrepareDownloadPlan = function (context) {
  var selectedIds = Array.isArray(context.selectedChapterIds)
    ? context.selectedChapterIds
    : [];
  var plan = context.chapterPlan;

  plan.chapters.forEach(function (chapter) {
    if (selectedIds.length > 0 && selectedIds.indexOf(chapter.id) < 0) {
      return;
    }

    var payload = getJson(chapter.chapterDataPath);
    chapter.pages = payload.pages.map(function (page) {
      return page.imageUrl;
    });
    delete chapter.chapterDataPath;
  });

  window.__nyxoviraChapterPlan = JSON.stringify(plan);
  return plan;
};

Nyxovira passes { selectedChapterIds, chapterPlan }. The function may return the final plan object or a JSON string. If it returns nothing, the app keeps the original plan.

Chapter formats

Use paragraphs for novels and pages for image chapters. The app also reads images for compatibility.

{
  "id": "chapter-forest-hunt",
  "title": "The Forest Hunt",
  "contentType": "novel",
  "paragraphs": [
    "First paragraph.",
    "Second paragraph."
  ]
}
{
  "id": "chapter-arrival",
  "title": "Arrival at the Ruins",
  "contentType": "images",
  "pages": [
    "https://example.com/page-001.png",
    "https://example.com/page-002.png"
  ]
}

Test in Nyxovira

Manual import is the normal development loop and also supports plugins intended only for personal use.

Keep plugin.json and the browser folder together inside the plugin folder.

In Nyxovira, open Sites, tap Import plugins, and select the plugin folder. You may also select a parent folder containing several plugin folders.

Open the supported site and verify work recognition, the chapter list, and the download.

After changing the files, import the folder again and repeat the test.

If the plugin is only for you, you are done. You do not need GitHub, a public catalog, or a plugin website.

If you want to share it

Publish in the official catalog

Use the Plugin Hub so the community can find the plugin under Online plugins.

Advanced: maintain an external store

This is the last and most involved option, intended for distributing a catalog of your plugins and plugins from other creators.

Publish in the official Plugin Hub

Use this option only when the plugin should appear in the official catalog. The public GitHub repository is the installation source; developers do not manually write a catalog entry.

plugin.json must contain a public HTTPS icon and a tags list with one language first, one to three content types, and adult last when needed.

Language tags

englishportuguesespanishjapanesekoreanchineseindonesianthaivietnamesefrenchgermanitalianrussianarabic

Content type tags

mangamanhuamanhwanovelwebtooncomicother

Optional classification

adult

Place it last when the source exposes adult-restricted material.

Keep plugin.json and browser/download_target.js in the repository.

Open the Plugin Hub and paste the GitHub repository URL.

Confirm the generated GitHub request and accept the current catalog rules.

Automation checks the files, icon, tags, hosts, and repository ownership.

A technically valid request is published in the catalog.

Only one visible plugin may cover a host. Responsibility, review, correction, and removal details are kept in the Terms and Plugin Catalog Rules.

External plugin store

Use this option only after the plugins are ready and tested. It is intended for anyone maintaining an independent distribution that may contain their own plugins and plugins from other creators.

A minimal external store can use this structure:

plugin-store/
|-- index.html
|-- catalog.json
`-- plugins/
    `-- my-plugin/
        |-- plugin.json
        `-- browser/
            `-- download_target.js

Host the folder at a public HTTPS address. The appearance, search, and plugin cards belong to the store itself; Nyxovira only needs to discover the catalog and receive the installation request. Add one object to the plugins list for every distributed plugin and identify its author and source site correctly.

Catalog discovery

Declare the catalog in the store's main page. A meta tag with the same name and a content URL is also supported.

<link rel="nyxovira-plugin-catalog" href="catalog.json">

Without a declaration, Nyxovira looks for catalog.json, catalog-store.json, and plugins.json in the page's directory. Users may also connect the JSON URL directly.

External catalog

{
  "schema_version": 1,
  "name": "My plugin store",
  "hub_url": "https://plugins.example.com/",
  "plugins": [{
    "id": "my-plugin",
    "name": "My Plugin",
    "author": "Author",
    "version": "1.0.0",
    "manifest_url": "plugins/my-plugin/plugin.json",
    "icon_url": "https://example.com/icon.png",
    "site_url": "https://example.com/",
    "tags": ["english", "manga"],
    "status": "active"
  }]
}

hub_url identifies the storefront when a JSON URL is connected directly. store_url and homepage are accepted aliases. Relative URLs are resolved against the catalog URL. Repository-based entries may use repository_url, repository_ref, and plugin_path.

Direct installation

This complete example creates the button, explains when the page is open outside the app, and displays the result returned by Nyxovira.

<button id="install-my-plugin" type="button">Install My Plugin</button>
<p id="install-status" aria-live="polite"></p>

<script>
  const catalogUrl = new URL("catalog.json", location.href).href;
  const status = document.querySelector("#install-status");

  document.querySelector("#install-my-plugin").addEventListener("click", () => {
    const bridge = globalThis.NyxoviraAndroidBridge
      || globalThis.ArchiveInkAndroidBridge;

    if (!bridge || typeof bridge.installCommunityPlugin !== "function") {
      status.textContent = "Open this site from Nyxovira to install.";
      return;
    }

    try {
      const result = JSON.parse(
        bridge.installCommunityPlugin(
          catalogUrl,
          JSON.stringify({ id: "my-plugin" })
        ) || "{}"
      );
      status.textContent = result.message
        || (result.success ? "Plugin installed." : "Could not install the plugin.");
    } catch (error) {
      status.textContent = "Could not complete the installation.";
    }
  });
</script>

When the store is open in a regular browser, the example tells the person to open it from Nyxovira. Inside the app, the button installs the matching plugin from the connected catalog.

Before publishing the store

Host the page, catalog, and plugin files at public HTTPS addresses.

For every plugin, accurately identify the author, source site, and manifest path.

Test the Install button by opening the store from its card under External sites in Nyxovira.

Test before sharing

Publish every file over HTTPS.

In Nyxovira, open Sites → External sites and connect the store page or directory.

Open the connected site from its card and tap Install.

Confirm the message returned by the installation.

Final checklist

Every plugin

Valid manifest fields; a working browser script; paragraphs for novels or pages for comics; no malware, credential collection, or access-control bypass.

Official Plugin Hub

A public repository owned by the requester; a public icon; accepted tags; no existing visible plugin for the same host; submission through the Plugin Hub.

External site

Page, catalog, and plugins published; correct author and source-site information; Install button tested by opening the store from Nyxovira.