Selene Plugin SDK

Build plugins for the Selene browser without modifying the browser source code.

Quick Start

  1. Create a folder in ~/.selene/plugins/my-plugin/
  2. Add a plugin.json manifest
  3. Add a main.js script
  4. Restart Selene — your plugin auto-loads

plugin.json

{
  "name": "My Awesome Plugin",
  "version": "1.0.0",
  "description": "Does cool stuff on YouTube",
  "author": "YourName",
  "main": "main.js",
  "enabled": true,
  "match": [
    "https://*.youtube.com/*",
    "https://youtube.com/*"
  ]
}
Fields
FieldRequiredDefaultDescription
nameyesPlugin display name
versionno"1.0.0"Semver version string
descriptionno""Short description
authorno""Author name
mainno"main.js"Entry JS file
enablednotrueToggle plugin on/off
matchyes[]URL patterns (glob)
URL Pattern Matching

Patterns use * as wildcard:

*://*.google.com/*        → all Google subdomains, any protocol
https://youtube.com/*     → only HTTPS YouTube
*://*/*                   → every page

main.js

Your script runs in the page's Main World (same context as the website). You have access to the full DOM and the SelenePlugin API.

Storage (persistent, scoped per plugin)
SelenePlugin.storage.set('key', 'value');
const val = SelenePlugin.storage.get('key');
SelenePlugin.storage.remove('key');
const allKeys = SelenePlugin.storage.keys();
DOM Utilities
// Run code when DOM is ready
SelenePlugin.dom.ready(function() {
  // your code here
});

// Inject CSS
SelenePlugin.dom.addStyle('body { background: #000 !important; }');

// Inject external script
SelenePlugin.dom.injectScript('https://example.com/lib.js');

// Wait for element to appear
SelenePlugin.dom.waitFor('.video-player', function(el) {
  console.log('Player found!', el);
});
HTTP
// GET text
SelenePlugin.http.get('https://api.example.com/data', function(err, text) {
  if (err) return;
  console.log(text);
});

// GET JSON
SelenePlugin.http.getJSON('https://api.example.com/data', function(err, data) {
  if (err) return;
  console.log(data);
});
Page Info
const url = SelenePlugin.page.url;       // full URL
const domain = SelenePlugin.page.domain; // hostname
const title = SelenePlugin.page.title;   // page title
Logging
SelenePlugin.log('Hello!');
SelenePlugin.warn('Warning!');
SelenePlugin.error('Error!');

Example Plugin: Dark Mode for YouTube

plugin.json

{
  "name": "YouTube Dark Mode",
  "version": "1.0.0",
  "description": "Forces dark mode on YouTube",
  "author": "Selene",
  "main": "main.js",
  "match": ["https://*.youtube.com/*"]
}

main.js

SelenePlugin.dom.ready(function() {
  SelenePlugin.dom.addStyle('ytd-app { background: #0f0f0f !important; }');
  SelenePlugin.log('Dark mode applied');
});

Example Plugin: Auto-Skip Ads

plugin.json

{
  "name": "Auto Skip Ads",
  "version": "1.0.0",
  "description": "Auto-clicks skip button on supported sites",
  "match": ["https://*.youtube.com/*"]
}

main.js

SelenePlugin.dom.ready(function() {
  setInterval(function() {
    var skipBtn = document.querySelector('.ytp-ad-skip-button');
    if (skipBtn) {
      skipBtn.click();
      SelenePlugin.log('Skipped ad');
    }
  }, 1000);
});

Plugin Distribution

Upload your plugin to the Selene Plugin Store via the browser UI (Menu → Plugins → Upload) or via the API:

POST https://rl-dev.de/api/browser/plugins

Users can then browse and download plugins from the Plugin Store dialog.

Tips

  • Each plugin runs in an IIFE — your variables are scoped
  • Errors are caught and logged to the browser console
  • localStorage is shared with the page; use SelenePlugin.storage for plugin-scoped data
  • Plugins are re-injected on every page navigation
  • The match patterns are case-insensitive
Plugin API Referenz Browser Übersicht
Wuppertaler Tafel AllOne The Outpace - Band Homepage