Plugin System Introduction
AN Player supports a plugin-based architecture that lets developers add new content sources to the app. Plugins are Node.js/TypeScript modules that act as bridges between AN Player and any data source or protocol.
TIP
The full plugin model definition is available at xeinebiu/android_anplayer_plugin. This is the best place to understand all available interfaces and models.
What is a Plugin?
A plugin is a TypeScript module that you write, compile into a single bundled JavaScript file using ncc, and distribute as a manifest file. AN Player runs this script inside an embedded Node.js runtime, so your plugin can connect to any server using any protocol, parse its responses, and return structured media data, all without any native Android code.
AN Player <-> Your Plugin <-> Your SourceWhen a user installs your plugin, AN Player copies the script to the device and runs it on demand inside the embedded runtime. Your plugin is never "installed" in the Android sense, just JavaScript evaluated in Node.js.
What Can a Plugin Do?
A plugin can implement any combination of the following capabilities:
| Capability | Description |
|---|---|
| Feed | Return a list of items shown on the Discover screen |
| Search | Accept a search query and return matching results |
| Auto-complete | Return live suggestions as the user types |
| Browse albums | Navigate folder/category/playlist hierarchies |
| Browse authors | List content by creator |
| Browse categories | List content by genre or topic |
| Stream playback | Resolve a media item URI to a playable stream URL |
You only need to implement the capabilities your data source supports. Everything else defaults to ExtractorNotImplementedError, which AN Player handles gracefully.
Every plugin is a factory function that receives a context object (including config and logger) and returns an object containing the extractor factories and classification helpers.
import { AnPlayerExtractor } from '@xeinebiu/anplayer-plugin-core';
const MyPlugin: AnPlayerExtractor = ({ config, logger }) => {
return {
async isSupported(uri) {
return uri.hostname === 'myapi.example.com';
},
async isAlbum(uri) {
return uri.pathname === '/album';
},
async isMediaTrack(uri) {
return uri.pathname === '/media';
},
async getFeedExtractor() {
// return your feed extractor here
},
// ... implement other extractors
};
};
export default MyPlugin;The factory pattern ensures that your plugin receives its unique configuration (like API keys or server URLs)
config: A string containing any user-supplied configuration (API keys, custom tokens, or serialized settings). The app doesn't enforce a format; it just stores the string and passes it back to your plugin. and a dedicated logger directly through its constructor. All methods are asynchronous, allowing you to perform I/O or other setup as needed.
IMPORTANT
Your plugin must be exported as the default export. AN Player expects the script to return a single factory function compatible with the AnPlayerExtractor signature.
AN Player identifies content by URIs. Your plugin's classification methods decide:
async isSupported(uri): does this plugin own this URI at all?async isAlbum(uri): is this URI a browseable container (folder, playlist, category)?async isMediaTrack(uri): is this URI a playable media item?
You construct these URIs yourself when returning data from your feed or album extractor, so you have full control over the scheme.
Error Handling
When a capability is not implemented, throw ExtractorNotImplementedError:
import { ExtractorNotImplementedError } from '@xeinebiu/anplayer-plugin-core';
// Inside an extractor method you chose not to implement:
throw new ExtractorNotImplementedError();AN Player catches this and either hides the feature or shows an appropriate message to the user.
Next Steps
- Getting Started: set up your dev environment and build a minimal plugin
- Example Scenario: understand the MediaVault API used in our guides
- Create a Plugin: implement the full MediaVault plugin step by step
- Build & Distribute: bundle, package, host, and install your plugin