Getting Started
This guide walks you through setting up a plugin development environment and building a minimal working plugin.
Prerequisites
- Node.js ≥ 18 and npm ≥ 9
- A text editor or IDE with TypeScript support (VS Code recommended)
- Basic familiarity with TypeScript
Verify your Node.js version:
node --version # should print v18.x.x or higher
npm --versionCreate the Project
Create a new directory and initialize it:
mkdir mediavault-plugin
cd mediavault-plugin
npm init -yInstall Dependencies
The plugin core is distributed as a .tgz archive on GitHub Releases. Add it to your package.json dependencies:
{
"dependencies": {
"@xeinebiu/anplayer-plugin-core": "https://github.com/xeinebiu/android_anplayer_plugin/releases/download/2.17.0/xeinebiu-anplayer-plugin-core-2.17.0.tgz"
},
"devDependencies": {
"typescript": "~5.7.3",
"@vercel/ncc": "^0.38.3"
}
}Then install:
npm installConfigure TypeScript
Create tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist"
},
"include": ["src/**/*"]
}Project Structure
mediavault-plugin/
├── src/
│ └── main.ts ← your plugin entry point
├── package.json
└── tsconfig.jsonCreate the src directory:
mkdir srcWrite a Minimal Plugin
Create src/main.ts with a plugin that always returns a single hardcoded media item. This lets you verify your build and install pipeline before connecting to a real API.
import {
AnPlayerExtractor,
createMedia,
createDirectStream,
} from '@xeinebiu/anplayer-plugin-core';
const MyPlugin: AnPlayerExtractor = ({ config, logger }) => {
// Config is a string passed by AN Player. The format is up to you.
return {
/**
* Determines if this plugin can handle the given URI.
*/
async isSupported(uri) {
return uri.hostname === 'mediavault.local';
},
/**
* Identifies if the URI points to a browsable container (album/folder).
*/
async isAlbum(_uri) {
return false;
},
/**
* Identifies if the URI points to a playable media item.
*/
async isMediaTrack(uri) {
return uri.pathname === '/media';
},
/**
* Returns an extractor for the home feed/discovery screen.
*/
async getFeedExtractor() {
return {
// next() should return an array of items for the next page.
// Return an empty array to signal the end of the list.
next: async () => [
createMedia({
id: 'test-video',
title: 'Test Video',
uri: 'https://mediavault.local/media?id=test-video',
}),
],
};
},
/**
* Returns an extractor for a specific media item.
*/
async getMediaExtractor(_uri) {
return {
getStream: async () =>
createDirectStream({
uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
}),
};
},
};
};
export default MyPlugin;INFO
createMedia, createAlbum, createDirectStream and other factory helpers are exported from the plugin core. They handle filling in default values so you only supply what you have.
The config and logger arguments passed to your plugin function allow you to handle user configuration and log messages to the AN Player console.
IMPORTANT
Ensure you use export default MyPlugin;. AN Player will not be able to load your plugin if the factory function is not the default export.
Build
Bundle your plugin into a single JavaScript file with ncc:
npx ncc build ./src/main.ts -m -o ./dist/-m: minify output-o ./dist/: output directory
After a successful build you will have dist/index.js, the file you embed in your plugin manifest.
Add a Build Script
Add a build script to package.json for convenience:
{
"scripts": {
"build": "ncc build ./src/main.ts -m -o ./dist/"
}
}Then build with:
npm run buildNext Steps
With a working build pipeline in place, move on to:
- Example Scenario: understand the API we will be mapping
- Create a Plugin: replace the hardcoded feed with real API calls